#include "sal.h"
#include "ctc_cli.h"
#include "usw/include/drv_enum.h"
#include "drv_api.h"
#include "usw/include/drv_common.h"
#include "usw/include/drv_chip_ctrl.h"
#include "ctc_dkit.h"
#include "ctc_dkit_common.h"
#include "ctc_usw_dkit_misc.h"
#include "ctc_usw_dkit.h"
#include "ctc_usw_dkit_dump_cfg.h"
#include "ctc_tmm_dik_serdes_reg.h"


#define CTC_DKIT_SERDES_PARAM_NONE 0xff
#define CTC_DKIT_SERDES_FIREWARE_FILE_HEADER_RSV_SIZE 0x1000
#define CTC_DIKT_TMM_PATTERN_NUM 15
#define CTC_DIKT_TMM_SERDES_REF_CLK_FREQ 15625
#define DKIT_SERDES_ID_MAX 100

#if (SDB_MEM_MODEL == SDB_MODE)
#define CTC_DIKT_TMM_SERDES_TWOS_TO_INT(twos_val, bit_width)     (twos_val > 0 ? (twos_val):(twos_val + (int)(1 << bit_width)))
#define CTC_DIKT_TMM_SERDES_INT_TO_TOWS(twos_val, bit_width)     (((twos_val >> (bit_width - 1)) & 0x1) == 0 ? twos_val : (twos_val - (int)(1 << bit_width)))
#else
#define CTC_DIKT_TMM_SERDES_TWOS_TO_INT(twos_val, bit_width)     (twos_val > 0 ? (twos_val):(twos_val + (1 << bit_width)))
#define CTC_DIKT_TMM_SERDES_INT_TO_TOWS(twos_val, bit_width)     (((twos_val >> (bit_width - 1)) & 0x1) == 0 ? twos_val : (twos_val - (1 << bit_width)))
#endif
    
#define CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(bin)      ((bin)^((bin)>>1))

#define CTC_DIKT_TX_TAP_VAL_MAX 62
#define CTC_DIKT_TX_TAP_VAL_MIN -40

#define CTC_DIKT_TMM_LANE_NUM_PER_HSS               8
#define CTC_DIKT_TMM_MAP_SERDES_TO_HSS_IDX(serdes_id)        ((serdes_id) / CTC_DIKT_TMM_LANE_NUM_PER_HSS)
#define CTC_DIKT_TMM_MAP_SERDES_TO_LANE_ID(serdes_id)        ((serdes_id) % CTC_DIKT_TMM_LANE_NUM_PER_HSS)

#define DKITS_SERDES_ID_CHECK(ID) \
    do { \
        if(ID >= DKIT_SERDES_ID_MAX) \
        {\
            CTC_DKIT_PRINT("serdes id %d exceed max id %d!!!\n", ID, DKIT_SERDES_ID_MAX-1);\
            return DKIT_E_INVALID_PARAM; \
        }\
    } while (0)
    
#define CTC_DIKT_TMM_SERDES_MSB_LSB_SWAP(x)     \
        do{\
            typeof(x) _x = 0;\
            uint8 index = 0;\
            for(index = 0; index < sizeof(x); index ++) \
            {\
                _x += ((x >> 8*index) & 0xff) << (8*((sizeof(x) - 1 - index)));\
            }\
            x = _x;\
        }while(0)

extern ctc_dkit_master_t* g_usw_dkit_master[CTC_DKITS_MAX_LOCAL_CHIP_NUM];

extern int32
sys_usw_datapath_get_lport_with_serdes(uint8 lchip, uint16 serdes_id, uint32* p_gport);
            
struct ctc_dkit_tmm_serdes_ctl_loopback_s
{
    uint16 serdes_id;
    uint8 oper;
    uint8 mode;
};
typedef struct ctc_dkit_tmm_serdes_ctl_loopback_s ctc_dkit_tmm_serdes_ctl_loopback_t;

struct ctc_tmm_dkit_misc_serdes_ber_s
{
    uint8 ber_n;
    uint8 ber_farc;
    int8 ber_pow;
};
typedef struct ctc_tmm_dkit_misc_serdes_ber_s ctc_tmm_dkit_misc_serdes_ber_t;

struct ctc_dkit_tmm_serdes_ctl_prbs_s
{
    uint8 lchip;
    uint16 serdes_id;
    uint8 oper;
    uint8 prbs_pattern;
    uint8 is_keep;
    uint32 delay_before_check;
    uint32 error_count;
    ctc_tmm_dkit_misc_serdes_ber_t ber;
    char *str;
};
typedef struct ctc_dkit_tmm_serdes_ctl_prbs_s ctc_dkit_tmm_serdes_ctl_prbs_t;

struct ctc_dkit_tmm_serdes_ctl_eye_s
{
    uint16 serdes_id;
    uint8 eye_type;
    uint32 read_times;
};
typedef struct ctc_dkit_tmm_serdes_ctl_eye_s ctc_dkit_tmm_serdes_ctl_eye_t;

struct ctc_dkit_tmm_serdes_ctl_ffe_s
{
    uint16 serdes_id;
    uint16 dest_serdes_id;
    uint8 prbs_pattern;
    uint32 threshold;//coefficient sum threshold
    uint32 delay;
    char *str;
    ctc_dkit_serdes_para_ffe_t *ffe;
};
typedef struct ctc_dkit_tmm_serdes_ctl_ffe_s ctc_dkit_tmm_serdes_ctl_ffe_t;

struct ctc_dkit_tmm_serdes_ctl_pol_check_s
{
    uint16 serdes_id;
    uint8 paired_serdes_id;
};
typedef struct ctc_dkit_tmm_serdes_ctl_pol_check_s ctc_dkit_tmm_serdes_ctl_pol_check_t;


struct ctc_dkit_tmm_serdes_ctl_dfe_s
{
    uint16 serdes_id;
    uint8 oper;
    uint8 delta;
    int8 taps[5];
    int32 taps_pam4[5];
};
typedef struct ctc_dkit_tmm_serdes_ctl_dfe_s ctc_dkit_tmm_serdes_ctl_dfe_t;

struct ctc_dkit_tmm_serdes_ctl_fw_s
{
    uint16 serdes_id;
    uint8 oper;
};
typedef struct ctc_dkit_tmm_serdes_ctl_fw_s ctc_dkit_tmm_serdes_ctl_fw_t;

struct ctc_dkit_tmm_serdes_ctl_bathtub_s
{
    uint16 serdes_id;
    uint8 oper;
    uint8 depth;
};
typedef struct ctc_dkit_tmm_serdes_ctl_bathtub_s ctc_dkit_tmm_serdes_ctl_bathtub_t;


struct ctc_dkit_tmm_serdes_fw_header_s
{
    uint32 hash_code;
    uint16 crc16;
    uint16 date;
    uint32 entry_point;
    uint32 length;
    uint32 ram_addr;
};
typedef struct ctc_dkit_tmm_serdes_fw_header_s ctc_dkit_tmm_serdes_fw_header_t;

struct ctc_tmm_dkit_misc_serdes_tx_taps_param_s
{
    uint8 serdes_id;
    int8 taps_param[5];/*pre2 pre1 main post1 post2*/
};
typedef struct ctc_tmm_dkit_misc_serdes_tx_taps_param_s ctc_tmm_dkit_misc_serdes_tx_taps_param_t;

enum ctc_dkit_tmm_serdes_pam4_or_nrz_mode_s
{
    CTC_DKIT_TMM_SERDES_PAM4_MODE,
    CTC_DKIT_TMM_SERDES_NRZ_MODE
};
typedef enum ctc_dkit_tmm_serdes_pam4_or_nrz_mode_s ctc_dkit_tmm_serdes_pam4_or_nrz_mode_t;

enum _ctc_tmm_dkit_serdes_eye_mon_collect_option_s
{
    CTC_DKIT_TMM_SERDES_EYE_MON_COLLECT_OPTION_NONE = 0,
    CTC_DKIT_TMM_SERDES_EYE_MON_COLLECT_OPTION_DESTRUCTIVE = 2,
    CTC_DKIT_TMM_SERDES_EYE_MON_COLLECT_OPTION_BATHTUB = 4
};
typedef enum _ctc_tmm_dkit_serdes_eye_mon_collect_option_s _ctc_tmm_dkit_serdes_eye_mon_collect_option_t;

struct ctc_dkit_tmm_serdes_ber_array_s
{
    uint8 size;
    uint8 ber_array[DKIT_SERDES_ID_MAX];
};
typedef struct ctc_dkit_tmm_serdes_ber_array_s ctc_dkit_tmm_serdes_ber_array_t;

struct ctc_dkit_tmm_serdes_ber_mon_s
{
    uint8 lchip;
    ctc_dkit_tmm_serdes_ber_array_t ber_array;
    uint32 dkit_tmm_prbs_err_cnt_mon[DKIT_SERDES_ID_MAX];
    uint32 dkit_tmm_prbs_err_cnt_carry[DKIT_SERDES_ID_MAX];
    sal_time_t dkit_tmm_prbs_rst_tv[DKIT_SERDES_ID_MAX];
};
typedef struct ctc_dkit_tmm_serdes_ber_mon_s ctc_dkit_tmm_serdes_ber_mon_t;

ctc_dkit_tmm_serdes_fw_header_t g_dkit_tmm_fm_header = {  \
        .hash_code = 0x945223,                          \
        .crc16 = 0x7bff,                                \
    };

sal_time_t g_dkit_tmm_prbs_rst_tv[DKIT_SERDES_ID_MAX];

uint64 _ctc_tmm_dkit_misc_serdes_multiplication(uint32 muilt_a, uint32 muilt_b);
uint32 _ctc_tmm_dkit_misc_serdes_dump_ISI(uint8 lchip, uint8 serdes_id, sal_file_t p_file);
uint32 _ctc_tmm_dkit_misc_serdes_PT_debug(uint8 lchip, uint8 serdes_id, uint16 mode, uint16 index, uint16 *data);
STATIC int32 _ctc_tmm_dkit_misc_write_serdes_wapper(uint8 lchip, uint16 serdes_id, uint16 type, uint32 addr_offset, uint16 mask, uint16 data);
uint8 _ctc_tmm_dkit_misc_get_serdes_mode(uint8 lchip, uint16 serdes_id);
STATIC int32 _ctc_tmm_dkit_misc_read_serdes_wapper(uint8 lchip, uint16 serdes_id, uint16 type, uint32 addr_offset, uint16 mask, uint16 *data);


STATIC int32
_ctc_tmm_dkit_internal_convert_serdes_addr(ctc_dkit_serdes_wr_t* p_para, uint32* addr, uint8* hss_id)
{
    uint8 lane_id = 0;

    DKITS_PTR_VALID_CHECK(p_para);
    DKITS_PTR_VALID_CHECK(addr);
    DKITS_PTR_VALID_CHECK(hss_id);
    
    *hss_id = CTC_DIKT_TMM_MAP_SERDES_TO_HSS_IDX(p_para->serdes_id);
    lane_id = CTC_DIKT_TMM_MAP_SERDES_TO_LANE_ID(p_para->serdes_id);
    
    if(CTC_DKIT_SERDES_LINK_TRAINING == p_para->type)
    {
        *addr = 0x0000;     
    }
    else if(CTC_DKIT_SERDES_ALL == p_para->type)
    {
        *addr = 0x0000;
    }
    else if (CTC_DKIT_SERDES_FW == p_para->type)
    {
        *addr = 0x0000;
    }

    *addr = (*addr  + p_para->addr_offset) | (lane_id << 16);

    CTC_DKIT_PRINT_DEBUG("hssid:%d, lane:%d\n", *hss_id, lane_id);

    return CLI_SUCCESS;
}

uint16
ctc_tmm_dkit_misc_serdes_adc_test_getmask(uint16 bit_s, uint16 bit_e)
{
    uint16 mask = 0;
    uint16 bit_one = 1;
    uint16 bit  = 0;

    if((15 < bit_s) || (15 < bit_e) || (bit_e < bit_s))
    {
        return 0xffff;
    }

    for(bit = bit_s; bit <= bit_e; bit++)
    {
        mask |= bit_one << bit;
    }
    mask = ~mask;
    
    return mask;
}

void
ctc_tmm_dkit_misc_serdes_adc_test(uint8 lchip, uint16 serdes_id, uint32 delay_s, uint8 section)
{
    uint32 delay_ms = 1000 * delay_s;
    uint8  idx;
    uint16 mask;
    uint16 val;
    uint16 test_case[13][14] = {
        {1, 0x00e1,  8, 0x00e1, 0, 9, 12, 15,  0x00e1, 2, 4, 1, 13, 15},
            
        {1, 0x00e4,  6, 0x00e4, 0, 7, 12, 9, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 10, 7, 12, 19, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 20, 7, 12, 29, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 30, 7, 12, 39, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 40, 7, 12, 49, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 50, 7, 12, 59, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 60, 7, 12, 69, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 70, 7, 12, 79, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 80, 7, 12, 89, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 90, 7, 12, 99, 0x00e4, 2, 4, 1, 13, 15},
        {1, 0x00e4,  6, 0x00e4, 100, 7, 12, 109, 0x00e4, 2, 4, 1, 13, 15},
            
        {1, 0x00f8,  7, 0x00f8, 0, 8, 12, 31,  0x00f8, 2, 4, 1, 13, 15},
    };
    char*  name_head  = "Condor2_Analog_";
    char*  test_name[13] = {
        "TX_Ln", 
        "RX_Ln_0to9", 
        "RX_Ln_10to19", 
        "RX_Ln_20to29", 
        "RX_Ln_30to39", 
        "RX_Ln_40to49", 
        "RX_Ln_50to59", 
        "RX_Ln_60to69", 
        "RX_Ln_70to79", 
        "RX_Ln_80to89", 
        "RX_Ln_90to99", 
        "RX_Ln_100to109", 
        "PLL_TXLn"};
    uint16 en         = 0;
    uint16 en_addr    = 0;
    uint16 bit        = 0;
    uint16 reg_addr1  = 0;
    uint16 init_val   = 0;
    uint16 bit_s1     = 0;
    uint16 bit_e1     = 0;
    uint16 end_val    = 0;
    uint16 reg_addr2  = 0;
    uint16 val2       = 0;
    uint16 val3       = 0;
    uint16 val4       = 0;
    uint16 bit_s2     = 0;
    uint16 bit_e2     = 0;
    uint8  start_idx  = 0;
    uint8  end_idx    = 0;

    if(12 < section)
    {
        start_idx = 0;
        end_idx   = 13;
    }
    else
    {
        start_idx = section;
        end_idx   = section+1;
    }

    CTC_DKIT_PRINT("===========================================================================================================\n");
    CTC_DKIT_PRINT("SecId TestName                       En EnAddr Bit RegAd1 IniVal BitS1 BitE1 EndVal RegAd2 Val2 Val3 Val4 BitS2 BitE2\n");
    for(idx = 0; idx < 13; idx++)
    {
        CTC_DKIT_PRINT("%-5u %s%-15s ", idx, name_head, test_name[idx]);
        CTC_DKIT_PRINT("%-2u 0x%04x %-3u 0x%04x %-6u %-5u %-5u %-6u 0x%04x %-4u %-4u %-4u %-5u %-5u %s\n", 
            test_case[idx][0], test_case[idx][1], test_case[idx][2], test_case[idx][3], 
            test_case[idx][4], test_case[idx][5], test_case[idx][6], test_case[idx][7], 
            test_case[idx][8], test_case[idx][9], test_case[idx][10], test_case[idx][11], 
            test_case[idx][12], test_case[idx][13], ((idx == section) || (12 < section)) ? "<<<<Run" : "");
    }
    CTC_DKIT_PRINT("===========================================================================================================\n");

    for(idx = start_idx; idx < end_idx; idx++)
    {
        en         = test_case[idx][0] ;
        en_addr    = test_case[idx][1] ;
        bit        = test_case[idx][2] ;
        reg_addr1  = test_case[idx][3] ;
        init_val   = test_case[idx][4] ;
        bit_s1     = test_case[idx][5] ;
        bit_e1     = test_case[idx][6] ;
        end_val    = test_case[idx][7] ;
        reg_addr2  = test_case[idx][8] ;
        val2       = test_case[idx][9] ;
        val3       = test_case[idx][10];
        val4       = test_case[idx][11];
        bit_s2     = test_case[idx][12];
        bit_e2     = test_case[idx][13];

        CTC_DKIT_PRINT(">>>> Test Start %s%s (total %u of 0~%u)\n", name_head, test_name[idx], idx, 12);
        CTC_DKIT_PRINT("===========================================================================================================\n");
        /*test.start(en_addr, bit, en)*/
        mask = ctc_tmm_dkit_misc_serdes_adc_test_getmask(bit, bit);
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, en_addr, mask, en);
        sal_task_sleep(1000);

        /*test.auto_test(reg_addr1,init_val, bit_s1, bit_e1, end_val, reg_addr2, val2, val3, val4, bit_s2, bit_e2, lane)*/
        for(val = init_val; val <= end_val; val++)
        {
            /*self.api.MdioWr(reg_addr1, data_w1)*/
            mask = ctc_tmm_dkit_misc_serdes_adc_test_getmask(bit_s1, bit_e1);
            (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, reg_addr1, mask, val);
            CTC_DKIT_PRINT(" test_point is 0x%04x = %u\n", reg_addr1, val);
            /*self.api.MdioWr(reg_addr2, data_w2)*/
            mask = ctc_tmm_dkit_misc_serdes_adc_test_getmask(bit_s2, bit_e2);
            (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, reg_addr2, mask, val2);
            CTC_DKIT_PRINT(" test_point is 0x%04x = %u, start wait...\n", reg_addr2, val2);

            CTC_DKIT_PRINT(">>>> Voltage test start, waiting %us, gao kuai dian!\n", delay_s);
            sal_task_sleep(delay_ms);
            CTC_DKIT_PRINT(">>>> Voltage test end (%u/%u in section %u)\n", 
                (val-init_val)*3+1, (end_val-init_val+1)*3, idx);

            /*self.api.MdioWr(reg_addr2, data_w3)*/
            mask = ctc_tmm_dkit_misc_serdes_adc_test_getmask(bit_s2, bit_e2);
            (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, reg_addr2, mask, val3);
            CTC_DKIT_PRINT(" test_point is 0x%04x = %u, start wait...\n", reg_addr2, val3);

            CTC_DKIT_PRINT(">>>> Voltage test start, waiting %us, gao kuai dian!\n", delay_s);
            sal_task_sleep(delay_ms);
            CTC_DKIT_PRINT(">>>> Voltage test end (%u/%u in section %u)\n", 
                (val-init_val)*3+2, (end_val-init_val+1)*3, idx);

            /*self.api.MdioWr(reg_addr2, data_w4)*/
            mask = ctc_tmm_dkit_misc_serdes_adc_test_getmask(bit_s2, bit_e2);
            (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, reg_addr2, mask, val4);
            CTC_DKIT_PRINT(" test_point is 0x%04x = %u, start wait...\n", reg_addr2, val4);

            CTC_DKIT_PRINT(">>>> Voltage test start, waiting %us, gao kuai dian!\n", delay_s);
            sal_task_sleep(delay_ms);
            CTC_DKIT_PRINT(">>>> Voltage test end (%u/%u in section %u)\n", 
                (val-init_val)*3+3, (end_val-init_val+1)*3, idx);
        }

        /*test.stop(en_addr, bit)*/
        mask = ctc_tmm_dkit_misc_serdes_adc_test_getmask(bit, bit);
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, en_addr, mask, 0);
        CTC_DKIT_PRINT(">>>> Test End %s%s (total %u of 0~%u)\n", name_head, test_name[idx], idx, 12);
        CTC_DKIT_PRINT("===========================================================================================================\n");
    }
}

void
_ctc_tmm_dkit_misc_serdes_collect_theta(uint8 lchip, uint16 serdes_id, uint16 value)
{
    uint16 data      = 0;
    uint16 bot       = 0;
    uint16 top       = 0;
    uint16 theta2    = 0;
    uint16 theta3    = 0;
    uint16 theta4    = 0;

    CTC_DKIT_PRINT("-----------------------------------------------------------------------\n");
    CTC_DKIT_PRINT("SERDES_ID   Bot   Top   Theta2   Theta3   Theta4\n");
    CTC_DKIT_PRINT("-----------------------------------------------------------------------\n");

    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xeb, 0xfff1, &data);
        bot = data;
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xeb, 0xff8f, &data);
        top = data;

        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xe9, 0xfc07, value);
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x171, 0x80ff, &data);
        theta2 = data;
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x171, 0xff80, &data);
        theta3 = data;
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x172, 0x80ff, &data);
        theta4 = data;
    }
    else
    {
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xeb, 0xfff1, &data);
        bot = data;
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xeb, 0xff8f, &data);
        top = data;

        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xe9, 0xfc07, value);
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x6c, 0xff80, &data);
        theta2 = data;
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x6d, 0x80ff, &data);
        theta3 = data;
        (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x6d, 0xff80, &data);
        theta4 = data;
    }

    CTC_DKIT_PRINT("%-11d 0x%-3x 0x%-3x 0x%-6x 0x%-6x 0x%-6x\n",
        serdes_id, bot, top, theta2, theta3, theta4);

    CTC_DKIT_PRINT("-----------------------------------------------------------------------\n");
}

int32
ctc_tmm_dkit_misc_read_serdes(void* para)
{
    uint32 addr = 0;
    uint8 hss_id = 0;
    ctc_dkit_serdes_wr_t* p_para = (ctc_dkit_serdes_wr_t*)para;

    DKITS_PTR_VALID_CHECK(p_para);
    DKITS_SERDES_ID_CHECK(p_para->serdes_id);
    CTC_DKIT_LCHIP_CHECK(p_para->lchip);
    
    if(CTC_DKIT_SERDES_FW == p_para->type)
    {
        ctc_tmm_dkit_misc_serdes_adc_test(p_para->lchip, p_para->serdes_id, p_para->addr_offset, 0xff);
    }
    else if(CTC_DKIT_SERDES_PLLA == p_para->type)
    {
        _ctc_tmm_dkit_misc_serdes_collect_theta(p_para->lchip, p_para->serdes_id, (uint16)p_para->addr_offset);
    }
    else
    {
        (void)_ctc_tmm_dkit_internal_convert_serdes_addr(p_para, &addr, &hss_id);

        (void)drv_chip_read_hss28g(p_para->lchip, hss_id, addr, (uint16*)(&p_para->data));

        CTC_DKIT_PRINT_DEBUG("read  chip id:%d, hss id:%d, addr: 0x%04x, value: 0x%04x\n", p_para->lchip, hss_id, addr, p_para->data);
    }
    
    return CLI_SUCCESS;
}

int32
ctc_tmm_dkit_misc_write_serdes(void* para)
{
    uint32 addr = 0;
    uint8 hss_id = 0;
    uint16 data = 0;
    ctc_dkit_serdes_wr_t* p_para = (ctc_dkit_serdes_wr_t*)para;

    DKITS_PTR_VALID_CHECK(p_para);
    DKITS_SERDES_ID_CHECK(p_para->serdes_id);
    CTC_DKIT_LCHIP_CHECK(p_para->lchip);

    if(CTC_DKIT_SERDES_FW == p_para->type)
    {
        (void)_ctc_tmm_dkit_misc_serdes_PT_debug(p_para->lchip, p_para->serdes_id, 
            (uint16)(p_para->addr_offset), p_para->data, &data);
        CTC_DKIT_PRINT(" PT_dbg (mode=%u idx=%u): %u\n", (uint16)(p_para->addr_offset), p_para->data, data);
    }
    else if(CTC_DKIT_SERDES_COMMON_PLL == p_para->type)
    {
        ctc_tmm_dkit_misc_serdes_adc_test(p_para->lchip, p_para->serdes_id, p_para->addr_offset, (uint8)(p_para->data));
    }
    else
    {
        _ctc_tmm_dkit_internal_convert_serdes_addr(p_para, &addr, &hss_id);

        drv_chip_write_hss28g(p_para->lchip, hss_id, addr, (uint16)(p_para->data));

        CTC_DKIT_PRINT_DEBUG("write chip id:%d, hss id:%d, addr: 0x%04x, value: 0x%04x\n", p_para->lchip, hss_id, addr, p_para->data);
    }

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_read_serdes_wapper(uint8 lchip, uint16 serdes_id, uint16 type, uint32 addr_offset, uint16 mask, uint16 *data)
{
    uint16 raw_data = 0;
    uint16 mask_op = ~mask;
    uint16 bit;
    
    ctc_dkit_serdes_wr_t ctc_dkit_serdes_wr;
    sal_memset(&ctc_dkit_serdes_wr, 0, sizeof(ctc_dkit_serdes_wr_t));

    ctc_dkit_serdes_wr.lchip = lchip;
    ctc_dkit_serdes_wr.serdes_id = serdes_id;
    ctc_dkit_serdes_wr.type = type;
    ctc_dkit_serdes_wr.addr_offset = addr_offset;

    ctc_tmm_dkit_misc_read_serdes(&ctc_dkit_serdes_wr);

    raw_data = (((uint16)(ctc_dkit_serdes_wr.data)) & mask_op);

    for(bit = 0; 0 == ((mask_op >> bit) & 0x1); bit++) ;

    *data = raw_data >> bit;

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_write_serdes_wapper(uint8 lchip, uint16 serdes_id, uint16 type, uint32 addr_offset, uint16 mask, uint16 data)
{
    uint16 mask_op = ~mask;
    uint16 bit = 0;
    
    ctc_dkit_serdes_wr_t ctc_dkit_serdes_wr;
    sal_memset(&ctc_dkit_serdes_wr, 0, sizeof(ctc_dkit_serdes_wr_t));

    ctc_dkit_serdes_wr.lchip = lchip;
    ctc_dkit_serdes_wr.serdes_id = serdes_id;
    ctc_dkit_serdes_wr.type = type;
    ctc_dkit_serdes_wr.addr_offset = addr_offset;

    if(0xffff == mask_op)
    {
        ctc_dkit_serdes_wr.data = data;
        ctc_tmm_dkit_misc_write_serdes(&ctc_dkit_serdes_wr);
    }
    else
    {
        ctc_tmm_dkit_misc_read_serdes(&ctc_dkit_serdes_wr);
    
        for(bit = 0; 0 == ((mask_op >> bit) & 0x1); bit++) ;
        
        data = (data << bit);

        ctc_dkit_serdes_wr.data = (((uint16)ctc_dkit_serdes_wr.data & mask) | data);
        
        ctc_tmm_dkit_misc_write_serdes(&ctc_dkit_serdes_wr);
    }

    return CLI_SUCCESS;
}

uint8 
_ctc_tmm_dkit_misc_get_serdes_mode(uint8 lchip, uint16 serdes_id)
{
    uint16 data = 0;
    uint8 mode = 0;

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xb0, 0xfffd, &data);/*0xb0[1]*/

    if(data)
    {
        mode = CTC_DKIT_TMM_SERDES_NRZ_MODE;
    }
    else
    {
        mode = CTC_DKIT_TMM_SERDES_PAM4_MODE;
    }
    
    return mode;
}

int32
_ctc_tmm_dkit_misc_serdes_fw_cmd(uint8 lchip, uint8 serdes_id, uint16 cmd, uint16 detail, uint16 expected_response, uint16 *result)
{
    uint8 time_out = 1; //True
    uint16 cnt = 0;
    uint16 response = 0;
    
    if(CTC_DKIT_SERDES_PARAM_NONE != detail)
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_CMD_DETAIL_ADDR, 0x0, detail);
    }

    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_CMD_ADDR, 0x0, cmd);

    for(cnt = 0; cnt < 1000; cnt++)
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_CMD_ADDR, 0x0, result);

        if((*result) != cmd)
        {
            time_out = 0; //False
            break;
        }
    }

    if(time_out)
    {
        //CTC_DKIT_PRINT("\nCommand 0x%04x timeout, is firmware running?\n",cmd);
        return CLI_ERROR;
    }

    if(expected_response != CTC_DKIT_SERDES_PARAM_NONE)
    {
        response = (*result >> 8) & 0xf;
        //CTC_DKIT_PRINT("\nresponse 0x%x\n", response);
        
        if(response != expected_response)
        {
            //CTC_DKIT_PRINT("\nError returned, code = 0x%04x\n",response);
            return CLI_ERROR;
        }
    }
    
    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_PT_debug(uint8 lchip, uint8 serdes_id, uint16 mode, uint16 index, uint16 *data)
{
    uint16 fw_debug_cmd = 0xB000;
    uint16 fw_cmd_detail_addr = 0x9816;
    uint16 cmd = 0;
    
    cmd = fw_debug_cmd + ((mode & 0xf) << 4);
    _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, cmd, index, 0xb, data); 
    
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, fw_cmd_detail_addr, 0x0, data);
    
    return CLI_SUCCESS;
}

int32
ctc_tmm_dkit_misc_serdes_dump_exit_code(uint8 lchip, uint8 serdes_id, sal_file_t p_file)
{
    uint16 data = 0;
    uint8  idx;
    uint16 reg_fw_data0 = 0x9f00;
    _ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, 0x8, 100, &data);
    CTC_DKIT_PRINT(" Exit codes (starts from earliest):\n");
    for(idx = 0; idx < 16; idx++)
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, (reg_fw_data0 + idx), 0x0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " 0x%04x\n", data);
    }

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_get_fw_reg(uint8 lchip, uint8 serdes_id, uint16 fw_addr, uint16 section, uint16 *data)
{
    uint16 result;

    _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_REG_READ_CMD + section, fw_addr, 0xe, &result);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_REG_VALUE_ADDR, 0, data);

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_set_fw_reg(uint8 lchip, uint8 serdes_id, uint16 fw_addr, uint16 data, uint16 section)
{
    uint16 result;

    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_REG_VALUE_ADDR, 0, data);
    _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_REG_WRITE_CMD + section, fw_addr, 0xe, &result);

    return CLI_SUCCESS;
}

int32
ctc_tmm_dkit_misc_serdes_fw_reg(uint8 lchip, uint32 fw_addr_raw, uint32 val_raw, uint8 serdes_id, uint16 section)
{
    uint16 fw_addr = (uint16)fw_addr_raw;
    uint16 val     = (uint16)val_raw;
    uint16 val_d   = 0;
    CTC_DKIT_PRINT("serdes_id %u, fw_addr_raw 0x%x, fw_addr 0x%04x, val_raw 0x%x, val 0x%04x, section %u\n", 
        serdes_id, fw_addr_raw, fw_addr, val_raw, val, section);
    if((0xffff < fw_addr_raw) && (0xffff < val_raw))
    {
        for(fw_addr = 0; fw_addr < 51; fw_addr++)
        {
            _ctc_tmm_dkit_misc_serdes_get_fw_reg(lchip, serdes_id, fw_addr, section, &val);
            val_d = (val > 0x8000) ? (val - 0xffff) : val;
            CTC_DKIT_PRINT("FW_Reg %2d: 0x%04X, %d\n", fw_addr, val, val_d);
        }
    }
    else if((0xffff >= fw_addr_raw) && (0xffff < val_raw))
    {
        _ctc_tmm_dkit_misc_serdes_get_fw_reg(lchip, serdes_id, fw_addr, section, &val);
        val_d = (val > 0x8000) ? (val - 0xffff) : val;
        CTC_DKIT_PRINT("FW_Reg %2d: 0x%04X, %d\n", fw_addr, val, val_d);
    }
    else
    {
        _ctc_tmm_dkit_misc_serdes_set_fw_reg(lchip, serdes_id, fw_addr, val, section);
    }
    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_fw_read_s16(uint8 lchip, uint8 serdes_id, uint16 offset, uint16 *data)
{
    uint16 reg_fw_data0 = 0x9f00;
    
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, reg_fw_data0 + offset, 0x0, data);
    
    *data = (((*data) & 0x8000) ? (*data - 0x10000) : (*data));
    
    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_get_fw_header(uint8 lchip)
{ 
    /*if(0 == g_dkit_tmm_fm_header_flag)
    {
        g_dkit_tmm_fm_header = (ctc_dkit_tmm_serdes_fw_header_t*)(g_dkits_tmm_firmware + CTC_DKIT_SERDES_FIREWARE_FILE_HEADER_RSV_SIZE);

        CTC_DIKT_TMM_SERDES_MSB_LSB_SWAP(g_dkit_tmm_fm_header->hash_code);
        CTC_DIKT_TMM_SERDES_MSB_LSB_SWAP(g_dkit_tmm_fm_header->date);
        CTC_DIKT_TMM_SERDES_MSB_LSB_SWAP(g_dkit_tmm_fm_header->crc16);
        CTC_DIKT_TMM_SERDES_MSB_LSB_SWAP(g_dkit_tmm_fm_header->length);
        CTC_DIKT_TMM_SERDES_MSB_LSB_SWAP(g_dkit_tmm_fm_header->entry_point);
        CTC_DIKT_TMM_SERDES_MSB_LSB_SWAP(g_dkit_tmm_fm_header->ram_addr);

        g_dkit_tmm_fm_header_flag = 1;
    }*/

    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_fw_hash(uint8 lchip, uint8 serdes_id)
{
    uint16 result = 0;
    uint16 low_word = 0;
    uint32 hash_code;

    _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_HASH_CMD, CTC_DKIT_SERDES_PARAM_NONE, 0xf, &result);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_CMD_DETAIL_ADDR, 0x0, &low_word);
    
    hash_code = ((result & 0xff) << 16) | low_word;

    return hash_code;
}

uint16
_ctc_tmm_dkit_misc_serdes_fw_crc(uint8 lchip, uint8 serdes_id)
{
    uint16 checksum_code = 0;
    _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_CRC_CMD, CTC_DKIT_SERDES_PARAM_NONE, 0xf, &checksum_code);
    
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_CMD_DETAIL_ADDR, 0x0, &checksum_code);

    return checksum_code;
}

uint16
_ctc_tmm_dkit_misc_serdes_fw_load_info(uint8 lchip, uint8 serdes_id)
{
    uint16 load_info_code = 0;
    uint16 actual_magic_word = 0;
    uint32 actual_hash_code = 0;
    uint16 actual_crc_code = 0;

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_LOAD_MAGIC_WORD_ADDR, 0x0, &actual_magic_word);
    actual_hash_code = _ctc_tmm_dkit_misc_serdes_fw_hash(lchip, serdes_id);
    actual_crc_code = _ctc_tmm_dkit_misc_serdes_fw_crc(lchip, serdes_id);

    _ctc_tmm_dkit_misc_serdes_get_fw_header(lchip);

    /*Firmware Downloaded and magic word is correct*/
    if((FW_LOAD_MAGIC_WORD_NRZ == actual_magic_word) || (FW_LOAD_MAGIC_WORD_PAM4 == actual_magic_word))
    {
        load_info_code |= 1;  
    }

    /* Firmware Downloaded and hash code is correct (hash code readback is valid only if FW is not halted)*/
    if(actual_hash_code == g_dkit_tmm_fm_header.hash_code)
    {
        load_info_code |= 2;
    }

    /*Firmware Downloaded and crc code is correct*/
    if(actual_crc_code == g_dkit_tmm_fm_header.crc16)
    {
        load_info_code |= 4;
    }

    return load_info_code;
}

/**********************************************************************************#
# This function checks:
#
# 1. Is any FW loaded, regardless if it is the correct FW , running or halted
#
***********************************************************************************/
uint8 
_ctc_tmm_dkit_misc_is_fw_loaded(uint8 lchip, uint8 serdes_id)
{
    uint8 stat = 0;
    uint16 load_info_code;

    load_info_code = _ctc_tmm_dkit_misc_serdes_fw_load_info(lchip, serdes_id);

    stat = load_info_code & 1;

    return stat;
}

/**********************************************************************************#
# This function checks:
#
# 1. If a FW is loaded and is running?
#
***********************************************************************************/
uint8 
_ctc_tmm_dkit_misc_serdes_is_fw_running(uint8 lchip, uint8 serdes_id)
{
    uint8 stat = 0;
    uint16 val_0;
    uint16 val_1;

    /*check the watchdog counter to see if FW is incrementing it*/
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_WATCHDOG_TIMER_ADDR, 0x0, &val_0);
    sal_task_sleep(1800); 
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_WATCHDOG_TIMER_ADDR, 0x0, &val_1);

    /*watchdog counter is moving, then FW is loaded and running*/
    if(val_1 != val_0)  
    {
        /*if FW is loaded but magic word is corrupted, correct it*/
        if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_LOAD_MAGIC_WORD_ADDR, 0x0, FW_LOAD_MAGIC_WORD_PAM4);
        }
        else
        {
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_LOAD_MAGIC_WORD_ADDR, 0x0, FW_LOAD_MAGIC_WORD_NRZ);
        }
        /*watchdog counter is moving, then FW is loaded and running*/
        stat = 1;  
    }
    else
    {
        /*watchdog counter is not moving, then FW is not loaded or halted*/
        stat = 0;  
    }

    return stat;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_set_eye_mon_collect(uint8 lchip, uint16 serdes_id, uint8 depth, uint8 option)
{
    char bar[102] = {0};
    const char *lable = "-\\|/";
    uint16 eye_mon_collection_start_word = 0;
    uint32 cnt = 0;
    uint16 eye_mon_curr_progress = 0;
    uint16 eye_mon_curr_progress_bak = 0;
    uint16 result;
    uint16 phy_rdy = 1;
    int32 ret = 0;
    int32 index = 0;

    eye_mon_collection_start_word = FW_EYEMON_START_CMD + (depth << 4) + option;
    
    ret = _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, eye_mon_collection_start_word, 0xff,0, &result);
    
    if(CLI_ERROR == ret)
    {
        return CLI_ERROR;
    }
    
    CTC_DKIT_PRINT("\n Eye Mon Data Collection Start. \n");
    
    while(((eye_mon_curr_progress & 0x00ff) <= 100) && (phy_rdy != 0))
    {
        if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_SD_RDY_ADDR, PAM4_RDY_MASK, &phy_rdy);
        }
        else
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_SD_RDY_ADDR, NRZ_RDY_MASK, &phy_rdy);
        }

        ret = _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_EYEMON_PROG_CMD, 0xff, 1, &result);

        eye_mon_curr_progress_bak = eye_mon_curr_progress;
        eye_mon_curr_progress = result & 0xff;
                
        if(CLI_ERROR == ret)
        {
            return CLI_ERROR;
        }

        CTC_DKIT_PRINT("[%-100s],%d%%,[%c]\r",bar, eye_mon_curr_progress_bak, lable[eye_mon_curr_progress_bak % 4]);
        sal_task_sleep(500);
       
        for(index = eye_mon_curr_progress_bak; index < eye_mon_curr_progress; index++)
        {
            bar[index] = '#';
        }
        bar[index]='\0';
        
        if(cnt > 100000)
        {
            CTC_DKIT_PRINT("\n>>>>EYE_MON Data Collection Timed Out\n");
            break;
        }

        cnt += 1;

        if(eye_mon_curr_progress_bak == 100)
        {
            break;
        }
    }

    if(cnt < 100000)
    {
        if(phy_rdy != 0)
        {
            CTC_DKIT_PRINT("\n Eye Mon Data Collection Done. \n");
        }
        else
        {
            CTC_DKIT_PRINT("\nLane don't Up!\n");
            return CLI_ERROR;
        }
    }

    return CLI_SUCCESS;
}

STATIC int32 
_ctc_tmm_dkit_misc_serdes_get_bathtub_common(uint8 lchip, uint8 serdes_id, uint8 vert_size_side, sal_file_t p_file)
{
    uint16 EYE_MON_DATA_START_ADDR = 0x9f00;
    uint16 vert_size_full = vert_size_side*2+1;
    uint16 status;
    uint8 index = 0;
    uint16 detail;
    uint16 *p_bath_data;
    int16 bath_data_index;
    uint16 extent = 0;
    int margin = 0;
    int32 ret = 0;

    p_bath_data = (uint16 *)mem_malloc(MEM_SYSTEM_MODULE, vert_size_full * sizeof(uint16));
    if (NULL == p_bath_data)
    {
        return CLI_ERROR;
    }

    sal_memset(p_bath_data, 0, vert_size_full * sizeof(uint16));

    for(margin = (-1)*vert_size_side; margin < vert_size_side; margin += 16)
    {
        detail = margin;
        ret = _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_EYEMON_READ_CMD, detail, 0xff, &status);
        if(CLI_ERROR == ret)
        {
            return CLI_ERROR;
        }

        if(((status >> 8) & 0xf) != 2)
        {
            for(index = 0; index < 16; index ++)
            {
                bath_data_index = margin + index + vert_size_side;
                if(bath_data_index < vert_size_full)
                {
                    p_bath_data[bath_data_index] = 0;
                }
            }
        }
        else
        {
            for(index = 0; index < 16; index ++)
            {
                bath_data_index = margin + index + vert_size_side;
                if(bath_data_index < vert_size_full)
                {
                    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, EYE_MON_DATA_START_ADDR + index, 0x0, (p_bath_data + bath_data_index));
                }
            }
        }
    }

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x9816, 0x0, &extent);

    CTC_DKITS_PRINT_FILE(p_file, " Bathtub:\n serdes : %d mode : %s\n", serdes_id, (vert_size_side == 63 ? "PAM4" : "NRZ"));
    CTC_DKITS_PRINT_FILE(p_file, " extent = %4d\n", extent);
    CTC_DKITS_PRINT_FILE(p_file, "\n bathtub_data = [\n");
    
    for(index = 0; index < vert_size_full; index ++)
    {
        if((0 == index % 8) && (0 != index))
        {
            CTC_DKITS_PRINT_FILE(p_file, " \n");
        }

        CTC_DKITS_PRINT_FILE(p_file, " %3u, ", p_bath_data[index]);
    }

    CTC_DKITS_PRINT_FILE(p_file, "\n ]\n");

    mem_free(p_bath_data);

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_get_bathtub_pam4(uint8 lchip, uint16 serdes_id, sal_file_t p_file)
{
    _ctc_tmm_dkit_misc_serdes_get_bathtub_common(lchip, serdes_id, 63, p_file);
    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_get_bathtub_nrz(uint8 lchip, uint16 serdes_id, sal_file_t p_file)
{
    _ctc_tmm_dkit_misc_serdes_get_bathtub_common(lchip, serdes_id, 48, p_file);
    return CLI_SUCCESS;
}

STATIC int32
ctc_tmm_dkit_misc_serdes_dump_bathtub(uint8 lchip, uint16 serdes_id, sal_file_t p_file)
{
    _ctc_tmm_dkit_misc_serdes_set_eye_mon_collect(lchip, serdes_id, 7, CTC_DKIT_TMM_SERDES_EYE_MON_COLLECT_OPTION_BATHTUB);

    if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_serdes_get_bathtub_pam4(lchip, serdes_id, p_file);
    }
    else
    {
        _ctc_tmm_dkit_misc_serdes_get_bathtub_nrz(lchip, serdes_id, p_file);
    }

    return CLI_SUCCESS;
}

STATIC int32
ctc_tmm_dkit_misc_serdes_do_bathtub(uint8 lchip, void *p_data)
{
    uint16 phy_rdy = 0;
    uint16 signal_detect = 0;
    uint16 serdes_id;
    static uint8 depth = 7;
    ctc_dkit_tmm_serdes_ctl_bathtub_t   *p_bathtub = NULL;
    static uint8 eye_mon_progress[DKIT_SERDES_ID_MAX] = {0};
    uint16 result = 0;
    static bool is_check[DKIT_SERDES_ID_MAX] = {FALSE};
    uint16 eye_mon_collection_start_word = 0;
    int32 ret = 0;

    DKITS_PTR_VALID_CHECK(p_data);
    CTC_DKIT_LCHIP_CHECK(lchip);

    p_bathtub = (ctc_dkit_tmm_serdes_ctl_bathtub_t *)p_data;

    serdes_id = p_bathtub->serdes_id;

    if(CTC_DKIT_SERDIS_CTL_ENABLE == p_bathtub->oper)
    {
        eye_mon_progress[serdes_id] = 0;
        is_check[serdes_id] = FALSE;
        depth = p_bathtub->depth;

        /*For cannel eye mon collect, and restart*/
        ret = _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, 0x4000, 0xff, 0, &result);

        eye_mon_collection_start_word = FW_EYEMON_START_CMD + (depth << 4) + CTC_DKIT_TMM_SERDES_EYE_MON_COLLECT_OPTION_BATHTUB;
        ret = _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, eye_mon_collection_start_word, 0xff,0, &result);
        
        if(CLI_ERROR == ret)
        {
            if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
            {
                _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_SD_RDY_ADDR, NRZ_RDY_MASK, &phy_rdy);
                _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_SD_RDY_ADDR, 0xfff7, &signal_detect);
            }
            else
            {
                _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_SD_RDY_ADDR, PAM4_RDY_MASK, &phy_rdy);
                _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_SD_RDY_ADDR, 0xff7f, &signal_detect);
            }
            
            CTC_DKIT_PRINT("  %% SerDes %d Collection Data Error. And Signal Detect is %s, PHY Ready is %s.\n", serdes_id,
                                                                         (signal_detect ? "YES":"NO"), (phy_rdy ? "YES":"NO"));
            return CLI_ERROR;
        }

        sal_task_sleep(500);

        ret = _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_EYEMON_PROG_CMD, 0xff, 1, &result);
        if(CLI_ERROR == ret)
        {
            return CLI_ERROR;
        }
        eye_mon_progress[serdes_id] = result & 0xff;

        is_check[serdes_id] = TRUE;

        if(eye_mon_progress[serdes_id] < 100)
        {
            CTC_DKIT_PRINT("  In Data Collection Progress . Please use cmd [serdes %d bathtub check] to get bathtub data.\n", serdes_id);
        }
        else
        {
            if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
            {
                _ctc_tmm_dkit_misc_serdes_get_bathtub_pam4(lchip, serdes_id, NULL);
            }
            else
            {
                _ctc_tmm_dkit_misc_serdes_get_bathtub_nrz(lchip, serdes_id, NULL);
            }
        }
    }
    else if(CTC_DKIT_SERDIS_CTL_CHECK == p_bathtub->oper)
    {
        if(is_check[serdes_id])
        {
            ret = _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_EYEMON_PROG_CMD, 0xff, 1, &result);
            if(CLI_ERROR == ret)
            {
                return CLI_ERROR;
            }

            eye_mon_progress[serdes_id] = result & 0xff;

            if(eye_mon_progress[serdes_id] < 100)
            {
                CTC_DKIT_PRINT("  In Data Collection Progress. Please use cmd [serdes %d bathtub check] to get bathtub data.\n", serdes_id);
            }
            else
            {
                if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
                {
                    _ctc_tmm_dkit_misc_serdes_get_bathtub_pam4(lchip, serdes_id, NULL);
                }
                else
                {
                    _ctc_tmm_dkit_misc_serdes_get_bathtub_nrz(lchip, serdes_id, NULL);
                }
            }
        }
        else
        {
            CTC_DKIT_PRINT("  Please use cmd [serdes %d bathtub dump depth DEPTH] to collection bathtub data. \n", serdes_id);
        }
    }

    return CLI_SUCCESS;
}

#if 0
STATIC int32
_ctc_tmm_dkit_misc_serdes_serial_loopback(uint8 lchip, uint16 serdes_id, uint8 enable)
{
    uint16 addr = 0;
    uint8 index = 0;
    uint16 data_list_00A0_00FF[96] = {
        0xE300, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0x0000, 0x0000, 0xfe00, 0x0000, 0x1400, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF83E, 0x4803, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xA424, 0x0000, 0x00C0, 
        0x2161, 0x6330, 0x7FC3, 0xE79B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x000F, 0xF002, 0xFFFC, 0x3000, 0x3002, 
        0x3000, 0x3000, 0xFFFE, 0x3000, 0x0002, 0x0000, 0x6EA0, 0x6490, 0x0006, 0x2222, 
        0x691C, 0x9230, 0x0000, 0x6D87, 0x7236, 0x4246, 0x0122, 0x8000, 0x8888, 0x8888, 
        0xFC00, 0x0C00, 0xAAAA, 0xAAAA, 0xAAAA, 0x0130, 0x966A, 0x96DB, 0x0000, 0x9297, 
        0x6DB4, 0x6A66, 0x8934, 0x421E, 0xC5EA, 0xFD30
    };

    uint16 data_list_0000_009F[160] = {
        0x266B, 0x0800, 0x0020, 0x7B33, 0x7068, 0xBD5D, 0x762B, 0x62C8, 0xC001, 0x7667, 
        0x6631, 0x3D15, 0x0080, 0x0002, 0x0080, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0600, 0x0020, 0x9400, 0x0024, 0x2A80, 0x8108, 0x1A00, 0x0028, 0x3400, 0x59AD, 
        0x20A0, 0x0100, 0x2310, 0x0000, 0x5000, 0x0208, 0x0012, 0x0200, 0x0800, 0xA080, 
        0x0002, 0x0180, 0x0090, 0x0500, 0x1000, 0x03DF, 0xB3FC, 0x0C82, 0x0015, 0x1010, 
        0x0000, 0x0000, 0x0094, 0x9B92, 0xDDBF, 0xF002, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0910, 0x4000, 0x0021, 0x0000, 0x4008, 0x0604, 0x0C00, 0x0100, 0x2042, 0xC800, 
        0x8251, 0x8100, 0x0000, 0x0028, 0x0811, 0x0800, 0x0900, 0x2220, 0x3000, 0x0810, 
        0x8000, 0x2041, 0x2602, 0x1080, 0x0088, 0x0100, 0x0000, 0x0080, 0x8012, 0x080A, 
        0x0000, 0x0040, 0x2A00, 0x200D, 0x0810, 0x0040, 0x0000, 0x0000, 0x0000, 0x0538, 
        0xBB80, 0x40A4, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E00, 0x0000, 0x0000, 0x000C, 0x009C, 
        0x5C10, 0x0C40, 0x7010, 0x0000, 0x8000, 0x0100, 0x9201, 0x1118, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
    };

    uint16 data_list_0100_019F[160] = {
        0x437D, 0x0201, 0x0026, 0x5933, 0x700A, 0x8E82, 0xA100, 0x4078, 0x688B, 0x2800, 
        0x0000, 0x0000, 0x8004, 0x1900, 0x0000, 0x0000, 0x0000, 0x0030, 0x0190, 0xDAB4, 
        0x0F70, 0xC708, 0xF066, 0xF7FF, 0x60F0, 0xAEE0, 0x5DB5, 0xB659, 0xE582, 0x4BF4, 
        0x9F40, 0x73DF, 0xC17B, 0xDCB7, 0xCB40, 0xA3FA, 0x21A0, 0x09E0, 0x0000, 0xB755, 
        0x9F5A, 0xF000, 0x09DA, 0x007A, 0x7E7F, 0x8021, 0x589D, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0400, 0x40FC, 0x0000, 0x0000, 0x00FF, 0xF000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0080, 0x0002, 0x073C, 0x0080, 0x0E15, 0x87D8, 0x3000, 0x0100, 
        0x5040, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0071, 0x0000, 0x7520, 0x2020, 0x0080, 
        0x8080, 0x0012, 0x0000, 0x0000, 0x6465, 0x6663, 0x2627, 0x2C2C, 0x6060, 0x1706, 
        0x6917, 0x4D17, 0x0000, 0x5936, 0x5A01, 0x0000, 0xFFFF, 0xC6FF, 0x2514, 0x8D53, 
        0xAEFF, 0x883D, 0x00A4, 0x0000, 0x8001, 0x0000, 0x0000, 0xFF08, 0x3500, 0x1000, 
        0xB800, 0x4902, 0x81FB, 0x477D, 0xC97E, 0x42FB, 0x41FB, 0x0000, 0x3701, 0x0000, 
        0x0000, 0x0000, 0x8000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
    };

    uint16 data_list_01F4_01FF[12] = {
        0xF0C8, 0x0084, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000
    };

    uint16 data_list_8000_80FC[253] = {
        0x2000, 0x0088, 0x6AB7, 0x2800, 0x0000, 0x009A, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8001, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0xA005, 0x0353, 0x04DF, 0x8203, 0x0000, 0x0000, 0x737D, 0x006A, 0x0005, 0x0001, 
        0x0000, 0x0000, 0x0000
    };

    uint16 data_list_8100_816C[109] = {
        0x0002, 0x0000, 0x0000, 0x394C, 0x6141, 0x0092, 0x0254, 0x0BE4, 0x0000, 0x1A90, 
        0x0330, 0x0039, 0x003E, 0x190E, 0x1912, 0x0035, 0x003E, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x2000, 0x0000, 0x0000, 0x0000, 0x1804, 0x0095, 0x0000, 0x4641, 0x4646, 
        0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03B9, 0xACA0, 0xC800, 
        0x0000, 0x1900, 0x190E, 0x1919, 0x1900, 0x0039, 0x0000, 0x0000, 0x0039, 0x0000, 
        0x0000, 0x0039, 0x0000, 0x0000, 0x039B, 0x0000, 0x14A1, 0x1284, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0x8000, 0x0000, 0x4000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0050, 0x0000, 0x0000, 0x0000, 0x1200, 0x0000, 0x0000, 0x0000, 
    };

    uint16 data_list_8200_8210[17] = {
        0x0000, 0x0000, 0xADCA, 0x9A00, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A9, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
    };

    uint16 data_list_8300_8349[74] = {
        0x0000, 0x0000, 0x0000, 0x2991, 0x0007, 0x6E60, 0x0001, 0x0000, 0x0000, 0x0000, 
        0x0802, 0x90E1, 0x6245, 0x40A8, 0x00A6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0001, 0x0000
    };

    uint16 data_list_8400_8457[88] = {
        0x0000, 0x0001, 0x0000, 0x0000, 0x0024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x3250, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    };

    uint16 addr_list[6] = {PLL_N_DDR, PLL_DIV4_ADDR,  0xb0, 0xa0,  0x179, 0x179};
    uint16 mask_list[6] = {PLL_N_MASK, PLL_DIV4_MASK, 0xfffe,  0xfffc, 0xfffe, 0xfe7f};
    uint16 data_list[6] = {0, 0, 0, 0, 0, 0};

    /*Disable*/
    if(!enable)
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xca, 0xfffd, 0);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xc5, 0x7fff, 0);
    }
    /*Enable*/
    else
    {
        /*Get Current Data Rate Related Configuration*/
         for(index = 0; index < 6; index ++)
         {
             _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr_list[index], mask_list[index], &data_list[index]);
         }
        
         /*---------------------------------------------
         * PAM4-NRZ Common Registers (R00A0 to R00FF)
         * ---------------------------------------------*/
         for(addr = 0x00a0; addr <= 0x00ff; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_00A0_00FF[addr - 0x00a0]);
         }
        
         /*---------------------------------------------
         * PAM4 Per-Lane Registers (R0000 to R009F)
         * ---------------------------------------------*/
         for(addr = 0x0000; addr <= 0x009f; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_0000_009F[addr]);
         }
        
         /*---------------------------------------------
         * NRZ Per-Lane Registers (R0100 to R019F)
         * ---------------------------------------------*/
         for(addr = 0x0100; addr <= 0x019F; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_0100_019F[addr - 0x0100]);
         }
        
         /*---------------------------------------------
         * fractional pll Registers (R01F4 to R01FF)
         * ---------------------------------------------*/
         for(addr = 0x01F4; addr <= 0x01FF; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_01F4_01FF[addr - 0x01F4]);
         }
        
         /*---------------------------------------------
         * aneg-ieee (R8000 to R80FC)
         * ---------------------------------------------*/
         for(addr = 0x8000; addr <= 0x80FC; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_8000_80FC[addr - 0x8000]);
         }
        
         /*---------------------------------------------
         * training reg (R8100 to R816C)
         * ---------------------------------------------*/
         for(addr = 0x8100; addr <= 0x816C; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_8100_816C[addr - 0x8100]);
         }
        
         /*---------------------------------------------
         * aneg_lt reg (R8200 to R8210)
         * ---------------------------------------------*/
         for(addr = 0x8200; addr <= 0x8210; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_8200_8210[addr - 0x8200]);
         }
        
         /*---------------------------------------------
         * aneg_cstm (R8300 to R8349)
         * ---------------------------------------------*/
         for(addr = 0x8300; addr <= 0x8349; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_8300_8349[addr - 0x8300]);
         }
        
         /*---------------------------------------------
         * anlt_reg (R8400 to R8457)
         * ---------------------------------------------*/
         for(addr = 0x8400; addr <= 0x8457; addr ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, data_list_8400_8457[addr - 0x8400]);
         }
        
         /*---------------------------------------------
         * Toggle Lane reset
         * ---------------------------------------------*/
         _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xb1ff, 0x0, 0xbd76);
         _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xb1fe, 0x0, 0x7400);
        
         /*Restore Data Rate Related Configuration*/
         for(index = 0; index < 6; index ++)
         {
             _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr_list[index], mask_list[index], data_list[index]);
         }
    }
   
    return CLI_SUCCESS;
}
#endif

int32 
_ctc_tmm_dkit_misc_serdes_set_rx_tx_serial_loopback(uint8 lchip, uint16 serdes_id, uint8 enable)
{
    if(enable)
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xcd, 0xffbf, 1);//Phase Rotator Polarity flip
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xcd, 0xffdf, 1);//TX Rotator disabled
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xce, 0xdfff, 0);//make sure frequency accumulator overwrite is disabled
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xce, 0xe001, 0);//frequency accumulator overwrite value if bit 13 is set to 1

        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x4b, 0xefff, 1);//Enable PLL Intp
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x4b, 0xf7ff, 1);//disable RX DTL Intp
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0xff, 0);//enable functional mode
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x9803, 0x7fff, 1);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x9803, 0x7fff, 1);//enable loopback fifo
    }
    else
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xcd, 0xffbf, 0);//Phase Rotator Polarity flip
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xcd, 0xffdf, 0);//TX Rotator disabled
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xce, 0xdfff, 0);//make sure frequency accumulator overwrite is disabled
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xce, 0xe001, 0);//frequency accumulator overwrite value if bit 13 is set to 1

        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x4b, 0xefff, 0);//Enable PLL Intp
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x4b, 0xf7ff, 0);//disable RX DTL Intp
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0xff, 0xef);//enable PRBS mode,  disable functional mode
    }

    return CLI_SUCCESS;
}


STATIC int32
_ctc_tmm_dkit_misc_serdes_loopback(uint8 lchip, void *p_data)
{
    CTC_DKIT_PRINT(" Feature not support!\n");
    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_get_datarate(uint8 lchip, uint16 serdes_id, uint32 *data_rate)
{
    uint8 div4 = 0;
    uint8 mode = 0;
    uint16 pll_n_val = 0;
    uint16 data = 0;
    uint32 fvo = 0;

    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        mode = 0;
    }
    else
    {
        mode = 1;
    }

    /*Get DataRate*/
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PLL_N_DDR, PLL_N_MASK, &pll_n_val);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PLL_DIV4_ADDR, PLL_DIV4_MASK, &data);
    div4 = (uint8)(data);
    fvo = CTC_DIKT_TMM_SERDES_REF_CLK_FREQ * pll_n_val * 4 / (div4 ? 4 : 1);

    if(1 == mode) /*PAM4 Mode*/
    {
        *data_rate = fvo * 2;
    }
    else  /*NRZ*/
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xb0, 0xfffe, &data);/*0xb0[0]*/
        if(0 == data)  /*Full Rate*/
        {
            *data_rate = fvo;
        }
        else
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0xfffc, &data);/*0xa0[1:0]*/
            switch(data)
            {
                case 0 :
                    *data_rate = fvo / 2;  /*Half Rate*/
                    break;
                case 1 :
                    *data_rate = fvo / 4;  /*Quarter Rate*/
                    break;
                case 2 :
                    *data_rate = fvo / 8;  /*Eighth Rate*/
                    break;
                case 3 :
                    *data_rate = fvo / 16;  /*Sixteenth Rate*/
                    break;
                default :
                    break;
            }
        }
    }

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_get_power_down_en(uint8 lchip, uint16 serdes_id, bool *enable)
{
    uint8 index = 0;
    uint16 val_list[6] = {0};
    uint16 reg_list[6] = {0x00f7, 0x00f7, 0x00ec, 0x00e9, 0x00e3, 0x00ff};
    uint16 mask_list[6] = {0x7fff, 0xbfff, 0xfffd, 0xfffb, 0xdfff, 0xffef};

    for(index = 0; index < 6; index ++)
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, reg_list[index], mask_list[index], (val_list + index));
    }

    if((0 == val_list[0]) && (0 == val_list[1]) && (0 == val_list[2]) && (0 == val_list[3]) && (0 == val_list[4]))
    {
        *enable = TRUE;
    }
    else
    {
        *enable = FALSE;
    }

    /*when special serdes, don't check 0xff[4]*/
    switch(serdes_id)
    {
        case 39:  /*MAC2DP0 F7*/
        case 43:  /*MAC3DP0 F3*/
        case 47:  /*MAC3DP0 F7*/
        case 87:  /*MAC2DP1 F7*/
        case 91:  /*MAC3DP1 F3*/
        case 95:  /*MAC3DP1 F7*/
        case 98:  /*CPUMAC  F2*/
            break;
        default:
            *enable &= ((0 == val_list[5]) ? TRUE : FALSE);
            break;
    }
    
    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_get_pll_lock(uint8 lchip, uint16 serdes_id, uint32 data_rate, uint16 *pll_lock)
{
    int8 index = 0;
    uint64 target_cnt = 0;
    uint16 addr_list[5] = {0x9822, 0x9823, 0x9824, 0x9825, 0x9825};
    uint16 reg_val[5] = {0x0000, 0x3fff, 0x0020, 0x1400, 0x1500};

    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x9826, 0x0, 0xffbc);
    
    if(125000 == data_rate)
    {
        reg_val[0] = 0x0000;
        reg_val[1] = 0x3fef;
        reg_val[2] = 0x0020;
    }
    else if(312500 == data_rate)
    {
        reg_val[0] = 0x0000;
        reg_val[1] = 0x9fd7;
        reg_val[2] = 0x0021;
    }
    else if(1031250 == data_rate)
    {
        reg_val[0] = 0x0002;
        reg_val[1] = 0x0f7b;
        reg_val[2] = 0x0020;
    }
    else if(2578125 == data_rate)
    {
        reg_val[0] = 0x0005;
        reg_val[1] = 0x26b4;
        reg_val[2] = 0x0021;
    }
    else if(5312500 == data_rate)
    {
        reg_val[0] = 0x0005;
        reg_val[1] = 0x4eaa;
        reg_val[2] = 0x0022;
    }
    else if(5156250 == data_rate)
    {
        reg_val[0] = 0x0005;
        reg_val[1] = 0x26b4;
        reg_val[2] = 0x0021;
    }
    else if(5625000 == data_rate)
    {
        reg_val[0] = 0x0005;
        reg_val[1] = 0x9e96;
        reg_val[2] = 0x0024;
    }
    else
    {
        target_cnt = _ctc_tmm_dkit_misc_serdes_multiplication(0xffbc , data_rate);
        target_cnt = target_cnt /CTC_DIKT_TMM_SERDES_REF_CLK_FREQ / 32;
    
        reg_val[0] = ((target_cnt >> 16) & 0xffff);
        reg_val[1] = (target_cnt & 0xffff);
    }

    /*set pll lock*/
    for(index = 0; index < 5; index++)
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr_list[index], 0x0, reg_val[index]);
    }
    
    sal_task_sleep(10);
    
    /*get pll lock 0x9829[15,14]*/
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x9829, 0x3fff, pll_lock);

    return CLI_SUCCESS;
}


STATIC int32
_ctc_tmm_dkit_misc_serdes_status(uint8 lchip, uint16 serdes_id, sal_file_t p_file)
{
    bool power_down_en;
    uint32 index = 0;    
    uint32 cmd = 0;
    uint32 iddq_val = 0;
    uint32 tbl_id = 0;
    uint32 field_id = 0;
    uint16 pll_cap_val = 0;
    uint16 phy_rdy = 0;
    uint16 signal_detect = 0;
    uint16 pll_lock = 0;
    uint32 data_rate = 0;
    uint8 mode = 0;
    uint8 dp_id = 0;
    uint8 txqm_id = 0;
    uint8 per_dp_hss_id = 0;
    uint8 step = 0;
    uint8 lane_id = 0;
    uint8 is_x16 = 0;
    uint16 tx_pol = 0, rx_pol = 0;
    uint16 tx_gc = 0, rx_gc = 0;
    uint16 tx_pc = 0, rx_pc = 0;
    uint16 tx_msblsb = 0, rx_msblsb = 0;
    char *vco_range_str[] = {
        " 0 [32.968750, 30.781250]",
        " 1 [0.000000, 0.000000] " ,
        " 2 [30.625000, 29.843750]",
        " 3 [29.687500, 29.062500]",
        " 4 [28.906250, 28.593750]",
        " 5 [28.437500, 28.125000]",
        " 6 [27.968750, 27.656250]",
        " 7 [27.500000, 27.343750]",
        " 8 [27.187500, 27.031250]",
        " 9 [26.875000, 26.718750]",
        "10 [26.562500, 26.250000]",
        "11 [26.093750, 25.937500]",
        "12 [25.781250, 25.625000]",
        "13 [25.468750, 25.312500]",
        "14 [25.156250, 25.000000]",
        "15 [24.843750, 24.843750]",
        "16 [24.687500, 24.531250]",
        "17 [24.375000, 24.218750]",
        "18 [24.062500, 23.906250]",
        "19 [23.750000, 23.750000]",
        "20 [23.593750, 23.437500]",
        "21 [23.281250, 23.281250]",
        "22 [23.125000, 22.968750]",
        "23 [22.812500, 22.812500]",
        "24 [22.656250, 22.500000]",
        "25 [22.343750, 22.343750]",
        "26 [22.187500, 22.031250]",
        "27 [21.875000, 21.875000]",
        "28 [21.718750, 21.718750]",
        "29 [21.562500, 21.562500]",
        "30 [21.406250, 21.406250]",
        "31 [21.250000, 21.250000]",
        "32 [21.093750, 20.937500]",
        "33 [20.781250, 20.781250]",
        "34 [20.625000, 20.625000]",
        "35 [20.468750, 20.468750]",
        "36 [20.312500, 20.312500]",
        "37 [20.156250, 20.156250]",
        "38 [20.000000, 20.000000]",
        "39 [19.843750, 19.843750]",
        "40 [19.687500, 19.687500]",
        "41 [19.531250, 19.531250]",
        "42 [19.375000, 19.375000]",
        "43 [19.218750, 19.218750]",
        "44 [19.062500, 19.062500]",
        "45 [0.000000, 0.000000] " ,
        "46 [18.906250, 18.906250]",
        "47 [18.750000, 18.750000]",
        "48 [18.593750, 18.593750]",
        "49 [18.437500, 18.437500]",
        "50 [18.281250, 18.281250]",
        "51 [0.000000, 0.000000] " ,
        "52 [18.125000, 18.125000]",
        "53 [17.968750, 17.968750]",
        "54 [0.000000, 0.000000] " ,
        "55 [17.812500, 17.812500]",
        "56 [17.656250, 17.656250]",
        "57 [17.500000, 17.500000]",
        "58 [0.000000, 0.000000] " ,
        "59 [17.343750, 17.343750]",
        "60 [17.187500, 17.187500]",
        "61 [17.031250, 17.031250]",
        "62 [16.875000, 16.875000]",
        "63 [16.718750, 15.000000]",
    };

    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        mode = 0;
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_SD_RDY_ADDR, NRZ_RDY_MASK, &phy_rdy);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_SD_RDY_ADDR, 0xfff7, &signal_detect);
    }
    else
    {
        mode = 1;
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_SD_RDY_ADDR, PAM4_RDY_MASK, &phy_rdy);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_SD_RDY_ADDR, 0xff7f, &signal_detect);
    }

    /*Get DataRate*/
    _ctc_tmm_dkit_misc_serdes_get_datarate(lchip, serdes_id, &data_rate);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PLL_LVCOCAP_DDR, PLL_LVCOCAP_MASK, &pll_cap_val);
    _ctc_tmm_dkit_misc_serdes_get_pll_lock(lchip, serdes_id, data_rate, &pll_lock);

   /*get connnect status*/
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xaf, 0xfdff, &tx_gc);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x42, 0xfffe, &rx_gc);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xaf, 0xfeff, &tx_pc);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x42, 0xfffd, &rx_pc);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xaf, 0xfbff, &tx_msblsb);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x43, 0x7fff, &rx_msblsb);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0xffdf, &tx_pol);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x161, 0xbfff, &rx_pol);

    _ctc_tmm_dkit_misc_serdes_get_power_down_en(lchip, serdes_id, &power_down_en);

    /*get CPUMAC IDDQ configure */
    if(96 <= serdes_id)
    {
        tbl_id  = CpuMacHssIddqEnable_t;
        field_id = CpuMacHssIddqEnable_hssIddq0En_f + (serdes_id % 4);
    }
    /*get NW IDDQ configure */
    else
    {
        dp_id = (serdes_id >= 48 ? 1: 0);
        per_dp_hss_id = (serdes_id / 8) % 6;

        if((per_dp_hss_id == 0) || (per_dp_hss_id == 1) || (per_dp_hss_id == 2) || (per_dp_hss_id == 3))
        {
            txqm_id = (per_dp_hss_id / 2) + (dp_id == 0 ? 0: 4);
            is_x16 = 1;
        }
        else
        {
            txqm_id = (per_dp_hss_id - 2) + (dp_id == 0 ? 0: 4);
            is_x16 = 0;
        }

        lane_id  = is_x16 ? (serdes_id % 16) : (serdes_id % 8);
        step     = (Dp1Mac0HssIddqEnable_t - Dp0Mac0HssIddqEnable_t) * dp_id;
        tbl_id   = Dp0Mac0HssIddqEnable_t + step + (txqm_id % 4);
        field_id = Dp0Mac0HssIddqEnable_hssIddq0En_f + lane_id;
    }

    cmd = DRV_IOR(tbl_id, field_id);
    DRV_FIELD_IOCTL(lchip, index, cmd, &iddq_val);

    CTC_DKITS_PRINT_FILE(p_file, "\n -------------------- Serdes %d Status --------------------\n", serdes_id);
    CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "Signal Detect", (signal_detect ? "Yes" : "No" ));
    CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "Lane Status", (phy_rdy ? "Up" : "Down" ));
    if(power_down_en)
    {
        CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "Mode", "-");
        CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "DataRate", "-");
        CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "VCO", "-");
    }
    else
    {
        CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "Mode", (mode ? "PAM4" : "NRZ"));
        CTC_DKITS_PRINT_FILE(p_file, " %-16s: %d.%05d\n", "DataRate", (data_rate / 100000), (data_rate % 100000));
        CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "VCO", ((pll_cap_val <= 63) ? vco_range_str[pll_cap_val] : "-"));
    }

    CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "Power Mode", (iddq_val ? "Low" : "Normal"));
    CTC_DKITS_PRINT_FILE(p_file, " %-16s: %s\n", "PLL Lock Status", ((3 == pll_lock) ? "Yes" : "No" ));

    CTC_DKITS_PRINT_FILE(p_file, "\n ---------------- Serdes %d Connect Status ----------------\n", serdes_id);
    CTC_DKITS_PRINT_FILE(p_file, " %-16s: %-8s -- %-16s: %-8s\n", "TX Polarity", (tx_pol ? "Normal" : "Inverse" ), "RX Polarity",(rx_pol ? "Inverse" : "Normal" ));
    CTC_DKITS_PRINT_FILE(p_file, " %-16s: %-8s -- %-16s: %-8s\n", "TX GrayCode", (tx_gc ? "En" : "Dis" ), "RX GrayCode", (rx_gc ? "En" : "Dis" ));
    CTC_DKITS_PRINT_FILE(p_file, " %-16s: %-8s -- %-16s: %-8s\n", "TX Precoder", (tx_pc ? "En" : "Dis" ), "RX Precoder", (rx_pc ? "En" : "Dis" ));
    CTC_DKITS_PRINT_FILE(p_file, " %-16s: %-8s -- %-16s: %-8s\n", "TX MSB-LSB", (tx_msblsb ? "En" : "Dis" ), "RX MSB-LSB", (rx_msblsb ? "En" : "Dis" ));
    CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------\n");

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_set_prbs_pat(uint8 lchip, uint8 serdes_id, uint8 dir, uint8 pat_type, bool enable)
{
    uint16 datapath_config_mapping[][5] =
            {
                /*prbstype, GrayCode, Precode, MSB-LSB*/
                    {0,        0,        0,       0},           /*0: NRZ-PRBS9*/
                    {1,        0,        0,       0},           /*1: NRZ-PRBS15*/
                    {2,        0,        0,       0},           /*2: NRZ-PRBS23*/
                    {3,        0,        0,       0},           /*3: NRZ-PRBS31*/        
                    {0,        0,        0,       0},           /*4 : PAM4-PRBS9*/
                    {1,        0,        0,       0},           /*5 : PAM4-PRBS13*/
                    {2,        0,        0,       0},           /*6 : PAM4-PRBS15*/
                    {3,        0,        0,       0},           /*7 : PAM4-PRBS31*/
                    {0,        1,        0,       0},           /*8 : PAM4-PRBS9Q*/
                    {1,        1,        0,       0},           /*9 : PAM4-PRBS13Q*/
                    {2,        1,        0,       0},           /*10 : PAM4-PRBS15Q*/
                    {3,        1,        0,       0},           /*11 : PAM4-PRBS31Q*/
                    {0,        1,        1,       0},           /*12 : PAM4-PRBS9QP*/
                    {1,        1,        1,       0},           /*13 : PAM4-PRBS13QP*/
                    {2,        1,        1,       0},           /*14 : PAM4-PRBS15QP*/
                    {3,        1,        1,       0},           /*15 : PAM4-PRBS31QP*/
            };

    /*RX Configure*/
    if(dir == 0) 
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, RX_GC_EN_ADDR, \
                                                                     RX_GC_EN_MASK, datapath_config_mapping[pat_type][1]);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, RX_PC_EN_ADDR, \
                                                                     RX_PC_EN_MASK, datapath_config_mapping[pat_type][2]);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, RX_MSB_LSB_ADDR, \
                                                                   RX_MSB_LSB_MASK, datapath_config_mapping[pat_type][3]);
            
        /*PAM4 PRBS patterns*/
        if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            /*0x43[6,5]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PRBS_MODE_SEL_ADDR_PAM4, \
                                                          PRBS_MODE_SEL_MASK_PAM4, datapath_config_mapping[pat_type][0]);
            /*0x41[15]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, RX_PAM4_EN_ADDR, RX_PAM4_EN_MASK, 1);
            /*0x43[4,3] 0b11*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x43, 0xffe7, (enable ? 3 : 0));
            /*0x44[15,8] 0h10*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x44, 0x00ff, (enable ? 0x10 : 0));
            /*0x44[5] 0b1*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x44, 0xffdf, (enable ? 1 : 0));
        }
        /*NRZ PRBS patterns*/
        else
        {
            /*0x161[13,12]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PRBS_MODE_SEL_ADDR_NRZ, \
                                                            PRBS_MODE_SEL_MASK_NRZ, datapath_config_mapping[pat_type][0]);
            /*0x41[15] 0b0*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, RX_PAM4_EN_ADDR, RX_PAM4_EN_MASK, 0);
            /*0x161[10]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x161, 0xfbff, (enable ? 1 : 0));
        }
    }
    /*TX Configure*/
    else     
    {
        /*0xa0[9,8]*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TEST_PATT_SEL_ADDR, \
                                                             TX_TEST_PATT_SEL_MASK, datapath_config_mapping[pat_type][0]);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_GC_EN_ADDR, \
                                                                      TX_GC_EN_MASK, datapath_config_mapping[pat_type][1]);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_PC_EN_ADDR, \
                                                                      TX_PC_EN_MASK, datapath_config_mapping[pat_type][2]);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_MSB_LSB_ADDR, \
                                                                    TX_MSB_LSB_MASK, datapath_config_mapping[pat_type][3]);

        /*PAM4 PRBS patterns*/
        if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            /*0xa0[15,13]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TEST_PATT_CTRL_ADDR, 0x1fff, (enable ? 0x7 : 0));
            /*0xa0[11]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0xf7ff, (enable ? 1 : 0));
        }
        /*NRZ PRBS patterns*/
        else
        {
            /*0xa0[15,13]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0x1fff, (enable ? 0x7 : 0));
            /*0xa0[11]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0xf7ff, (enable ? 1 : 0));
            /*0xb0[11]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xb0, TX_NRZ_PRBS_EN_MASK, (enable ? 1 : 0));
            /*0xb0[14]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xb0, TX_NRZ_PRBS_GEN_EN_MASK, (enable ? 1 : 0));
        }
    }

    return CLI_SUCCESS;
    
}

int32
_ctc_tmm_dkit_misc_serdes_set_test_pat(uint8 lchip, uint8 serdes_id, uint8 pat_type, bool enable)
{
    uint8 index = 0;
    uint16 test_patt_config_mapping[][4] ={
           /*0xa1,           0xa2,           0xa3,        0xa4*/
            {0x00FF,        0x00FF,        0x00FF,       0x00FF},           /*0: Squareware(8081)*/
            {0xAAAA,        0xAAAA,        0xAAAA,       0xAAAA}};          /*1: PRBS1T(1010)*/

    index = pat_type - 13;
            
    /*0xa1*/
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TEST_PATT_ADDR_4, \
                                                                   0x0, enable ? test_patt_config_mapping[index][0] : 0x0000);
    /*0xa2*/
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TEST_PATT_ADDR_3, \
                                                                   0x0, enable ? test_patt_config_mapping[index][1] : 0x0000);
    /*0xa3*/
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TEST_PATT_ADDR_2, \
                                                                   0x0, enable ? test_patt_config_mapping[index][2] : 0x0000);
    /*0xa4*/
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TEST_PATT_ADDR_1, \
                                                                   0x0, enable ? test_patt_config_mapping[index][3] : 0x0000);

    /*0xa0[15]*/
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0x7fff, enable ? 0 : 1);
    /*0xa0[13]*/
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0xdfff, enable ? 1 : 0);
 
    return CLI_SUCCESS;
    
}

int32
_ctc_tmm_dkit_misc_serdes_get_prbs_pat_by_mode(uint8 lchip, uint8 serdes_id, uint8 prbs_mode, uint8 *pat_type)
{
    uint16 nrz_prbs_bitmap = 0x1d;     /*0b0 0000 0001 1101   "PRBS9", "PRBS15", "PRBS23", "PRBS31"*/
    uint16 pam4_prbs_bitmap = 0x1ff7;  /*0b1 1111 1111 0111   "PRBS9x", "PRBS13x", "PRBS15x", "PRBS31x"*/
    
    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        /*Parameter Check*/
        if(1 != ((nrz_prbs_bitmap >> prbs_mode) & 0x1))
        {
            CTC_DKIT_PRINT("%% NRZ Mode Only Support : PRBS9, PRBS15, PRBS23, PRBS31.\n");
            return CLI_ERROR;
        }

        switch(prbs_mode)
        {
            case 0:
               *pat_type = 0;
               break;
            case 2:
                *pat_type = 1;
                break;
            case 3:
                *pat_type = 2;
                break;
            case 4:
            default:
                *pat_type = 3;
                break;
        }
    }
    else
    {
        /*Parameter Check*/
        if(1 != ((pam4_prbs_bitmap >> prbs_mode) & 0x1))
        {
            CTC_DKIT_PRINT("%% PAM4 Mode Don't   Support PRBS23.\n");
            return CLI_ERROR;
        }

        if((prbs_mode <= 4))
        {
            switch(prbs_mode)
            {
                case 0:
                    *pat_type = 4;
                    break;
                case 1:
                    *pat_type = 5;
                    break;
                case 2:
                    *pat_type = 6;
                    break;
                case 4:
                default:
                    *pat_type = 7;
                    break;
            }
        }
        else
        {
            *pat_type = (prbs_mode - 4) + 7;
        }
    }
    
    return CLI_SUCCESS;
}


int32
_ctc_tmm_dkit_misc_serdes_prbs_en(uint8 lchip, ctc_dkit_tmm_serdes_ctl_prbs_t *p_prbs)
{
    int32 ret = CLI_SUCCESS;
    uint16 serdes_id = 0;
    uint8 pat_type = 0;
    bool enable;
    uint16 prbs_en = 0;

    enable = (CTC_DKIT_SERDIS_CTL_ENABLE == p_prbs->oper ? TRUE : FALSE);
    serdes_id = p_prbs->serdes_id;

    /*check prbs whether is already enable.*/
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xa0, 0xf7ff, &prbs_en);  /*0xa0[11]*/

    /* prbs or test pattern is already enable, do not need operation */
    if(enable && prbs_en)
    {
        return CLI_EOL;
    }
    
    /* 13: Squareware(8081), 14: PRBS1T(1010)*/
    if((13 == p_prbs->prbs_pattern) || ((14 == p_prbs->prbs_pattern)))
    {        
        _ctc_tmm_dkit_misc_serdes_set_test_pat(lchip, p_prbs->serdes_id, p_prbs->prbs_pattern, enable);
    }
    else
    {
        ret = _ctc_tmm_dkit_misc_serdes_get_prbs_pat_by_mode(lchip, serdes_id, p_prbs->prbs_pattern, &pat_type);
        if(CLI_ERROR == ret)
        {
            return CLI_ERROR;
        }
        _ctc_tmm_dkit_misc_serdes_set_prbs_pat(lchip, p_prbs->serdes_id, 1, pat_type, enable);
    }
   
    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_get_prbs_cnt(uint8 lchip, uint8 serdes_id)
{
    uint16 data_low = 0;
    uint16 data_high = 0;
    uint32 err_cnt = 0;
    
    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_PRBS_CNT_ADDR, 0x0, &data_high);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_PRBS_CNT_ADDR + 1, 0x0, &data_low);
    }
    else
    {   
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR, 0x0, &data_high);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR + 1, 0x0, &data_low);
    }

    err_cnt = (data_high << 16) + data_low;

    return err_cnt;
}

int32
_ctc_tmm_dkit_misc_serdes_set_prbs_cnt_rst(uint8 lchip, uint8 serdes_id, ctc_dkit_tmm_serdes_ber_mon_t *ber_mon)
{
    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x161, 0x7fff, 1);/*0x161[15]*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x161, 0x7fff, 0);/*0x161[15]*/
    }
    else
    {   
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x43, 0xfffe, 1);/*0x43[0]*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x43, 0xfffe, 0);/*0x43[15]*/
    }
    
    sal_time(&ber_mon->dkit_tmm_prbs_rst_tv[serdes_id]);

    return CLI_SUCCESS;
}

uint64
_ctc_tmm_dkit_misc_serdes_multiplication(uint32 muilt_a, uint32 muilt_b)
{
    uint8 index = 0;
    uint8 muilt_u8 = 0;
    uint32 muiltplier = 0;
    uint32 muiltplicand = 0;
    uint64 base[4] = {1, 256, 65536, 16777216};
    uint64 result = 0;

    if(muilt_a < muilt_b)
    {
        muiltplier = muilt_a;
        muiltplicand = muilt_b;
    }
    else
    {
        muiltplier = muilt_b;
        muiltplicand = muilt_a;
    }

    for(index = 0; index < 4; index ++)
    {
        muilt_u8 = ((muiltplicand) >> (index * 8)) & 0xff;
        result += base[index] * (muilt_u8 * (muiltplier));
    }

    return result;
}

int32
_ctc_tmm_dkit_misc_serdes_get_prbs_ber(uint8 lchip, uint8 serdes_id, ctc_dkit_tmm_serdes_ber_mon_t *ber_mon, ctc_tmm_dkit_misc_serdes_ber_t *ber)
{  
    sal_time_t cur_tv;
    int32 power_10 = 1;
    uint32 prbs_accum_time_s = 0;
    uint32 datarate = 0;
    uint32 err_cnt_32 = 0;
    uint64 err_cnt_64 = 0;
    uint64 ber_val = 0;
    uint32 ber_val_low_u32 = 0;
    uint32 ber_val_high_u32 = 0;
    uint64 ber_val_low_u64 = 0;
    uint64 ber_val_high_u64 = 0;
    uint64 time_rate = 0;
    uint8 len = 1;
    uint8 err_cnt_len = 1;
    uint8 index = 0;
    uint32 *p_err_cnt = NULL;
    uint64 data_tmp;

    _ctc_tmm_dkit_misc_serdes_get_datarate(lchip, serdes_id, &datarate);

    err_cnt_32 = _ctc_tmm_dkit_misc_serdes_get_prbs_cnt(lchip, serdes_id);
    if(err_cnt_32 < ber_mon->dkit_tmm_prbs_err_cnt_mon[serdes_id])
    {
        ber_mon->dkit_tmm_prbs_err_cnt_mon[serdes_id] = err_cnt_32;
        ber_mon->dkit_tmm_prbs_err_cnt_carry[serdes_id] ++;
    }
    
    p_err_cnt = (uint32*)&err_cnt_64;
    sal_memcpy(p_err_cnt, &err_cnt_32,sizeof(uint32));
    sal_memcpy(p_err_cnt + 1, &(ber_mon->dkit_tmm_prbs_err_cnt_carry[serdes_id]), sizeof(uint32));

    sal_time(&cur_tv);

    prbs_accum_time_s = (uint32)(cur_tv - ber_mon->dkit_tmm_prbs_rst_tv[serdes_id]);

    time_rate = _ctc_tmm_dkit_misc_serdes_multiplication(prbs_accum_time_s, datarate);

    /*CTC_DIKT_TMM_GET_DATA_LENGTH(err_cnt_64, err_cnt_len);*/
    data_tmp = err_cnt_64;
    err_cnt_len = 1;
    while(data_tmp / 10)
    {
        data_tmp /= 10;
        err_cnt_len++;
    }

    /*CTC_DIKT_TMM_GET_DATA_LENGTH(time_rate, len);*/
    data_tmp = time_rate;
    len = 1;
    while(data_tmp / 10)
    {
        data_tmp /= 10;
        len++;
    }

    ber->ber_pow = -9 + 5;

    ber_val_low_u32 = (err_cnt_64 & 0xffffffff);
    ber_val_high_u32 = ((err_cnt_64 >> 32) & 0xffffffff);

    if(err_cnt_64 > time_rate)
    {

        ber_val_high_u64 = _ctc_tmm_dkit_misc_serdes_multiplication(ber_val_high_u32, 100);
        ber_val_low_u64 = _ctc_tmm_dkit_misc_serdes_multiplication(ber_val_low_u32, 100);

        ber_val_high_u32 = (ber_val_high_u64 & 0xffffffff) + ((ber_val_low_u64 >> 32) & 0xffffffff);
        ber_val_low_u32 = (ber_val_low_u64 & 0xffffffff);

        p_err_cnt = (uint32*)&ber_val;
        sal_memcpy(p_err_cnt, &ber_val_low_u32,sizeof(uint32));
        sal_memcpy(p_err_cnt + 1, &ber_val_high_u32, sizeof(uint32));

        ber_val /= time_rate;
        ber->ber_pow -= 2; 
    }
    else
    {
        for(index = 0; index < ((len - err_cnt_len) + 3); index ++)
        {
            ber_val_high_u64 = _ctc_tmm_dkit_misc_serdes_multiplication(ber_val_high_u32, 10);
            ber_val_low_u64 = _ctc_tmm_dkit_misc_serdes_multiplication(ber_val_low_u32, 10);

            ber_val_high_u32 = (ber_val_high_u64 & 0xffffffff) + ((ber_val_low_u64 >> 32) & 0xffffffff);
            ber_val_low_u32 = (ber_val_low_u64 & 0xffffffff);

            p_err_cnt = (uint32*)&ber_val;
            sal_memcpy(p_err_cnt, &ber_val_low_u32,sizeof(uint32));
            sal_memcpy(p_err_cnt + 1, &ber_val_high_u32, sizeof(uint32));

            ber_val_low_u32 = (ber_val & 0xffffffff);
            ber_val_high_u32 = ((ber_val >> 32) & 0xffffffff);
        }

        /*CTC_DIKT_TMM_GET_DATA_LENGTH(ber_val, len);*/
        data_tmp = ber_val;
        len = 1;
        while(data_tmp / 10)
        {
            data_tmp /= 10;
            len++;
        }

        ber->ber_pow -= (len - err_cnt_len); 
        ber_val /= time_rate;
    }

    /*CTC_DIKT_TMM_GET_DATA_LENGTH(ber_val, len);*/
    data_tmp = ber_val;
    len = 1;
    while(data_tmp / 10)
    {
        data_tmp /= 10;
        len++;
    }

    for(index = 0; index < (len - 1); index++)
    {
        power_10 *= 10;
    }

    ber->ber_n = ber_val / power_10;
    
    if(len <= 3)
    {
        ber->ber_farc = ber_val % power_10;
    }
    else
    {
        ber->ber_farc = ber_val % power_10 / (power_10 / 100);
    }

    ber->ber_pow += (len -1);

    if((0 == ber->ber_farc) && (0 == ber->ber_n))
    {
        ber->ber_pow = 0;
    }

    return CLI_SUCCESS;
}

STATIC void
_ctc_tmm_dkit_misc_serdes_monitor_prbs_ber_handler(void* arg)
{
    ctc_dkit_tmm_serdes_ber_mon_t* ber_mon = *(ctc_dkit_tmm_serdes_ber_mon_t**)arg;
    uint8 lchip = 0;
    uint8 index = 0;
    uint16 serdes_id = 0;
    uint32 err_cnt = 0;

    while (1)
    {
        lchip = ber_mon->lchip;
        if (g_usw_dkit_master[lchip]->monitor_task[CTC_DKIT_MONITOR_TASK_PRBS_BER].task_end)
        {
            goto End;
        }

        for(index = 0; index < ber_mon->ber_array.size; index ++)
        {
            serdes_id = ber_mon->ber_array.ber_array[index];
            err_cnt = _ctc_tmm_dkit_misc_serdes_get_prbs_cnt(lchip, serdes_id);

            /*PRBS Error Count overflow*/
            if(err_cnt < ber_mon->dkit_tmm_prbs_err_cnt_mon[serdes_id])
            {
                ber_mon->dkit_tmm_prbs_err_cnt_carry[serdes_id] ++;
            }

            ber_mon->dkit_tmm_prbs_err_cnt_mon[serdes_id] = err_cnt;
        }
            
        sal_task_sleep(1000);
    }

End:
    return;
}

int32
_ctc_tmm_dkit_misc_serdes_ber_array_add(uint8 serdes_id, ctc_dkit_tmm_serdes_ber_array_t* ber_array)
{
    uint8 index = 0;

    for(index = 0; index < ber_array->size; index ++)
    {
        if(ber_array->ber_array[index] == serdes_id)
        {
            return CLI_SUCCESS; 
        }
    }
    
    ber_array->ber_array[ber_array->size] = serdes_id;
    ber_array->size ++;

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_ber_array_remove(uint8 serdes_id, ctc_dkit_tmm_serdes_ber_array_t* ber_array)
{
    uint8 index = 0;
    int pos = -1;

    for(index = 0; index < ber_array->size; index ++)
    {
        if(ber_array->ber_array[index] == serdes_id)
        {
            pos = index;
            break;
        }
    }

    if(-1 < pos)
    {
        for(index=pos+1; index < ber_array->size; index ++)
        {
            ber_array->ber_array[index - 1] = ber_array->ber_array[index];
        }

        ber_array->size --;
    }

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_prbs_check(uint8 lchip, ctc_dkit_tmm_serdes_ctl_prbs_t *p_prbs, bool* pass)
{
    int32 ret = CLI_SUCCESS;
    uint8 task_id = CTC_DKIT_MONITOR_TASK_PRBS_BER;
    uint16 serdes_id = 0;
    uint32 delay = 0;
    uint8 is_keep = 0;
    uint32 err_cnt = 0;
    uint8 pat_type = 0;
    uint16 rst_cnt_flag = 0;
    uint16 chk_enable = 0;
    ctc_tmm_dkit_misc_serdes_ber_t ber;
    static ctc_dkit_tmm_serdes_ber_mon_t ber_mon = {.ber_array.size = 0};
    ctc_dkit_tmm_serdes_ber_mon_t *p_ber_mon = &ber_mon;
    char buffer[SAL_TASK_MAX_NAME_LEN] = {0};
        
    serdes_id = p_prbs->serdes_id;

    delay = p_prbs->delay_before_check;
    
    is_keep = p_prbs->is_keep;

    ber_mon.lchip = p_prbs->lchip;

    /*1. Get rst flag : From PRBS Check Disable to PRBS Check Enable, need clear prbs error cnt */
    if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        /*0x44[5] 0b1*/
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x44, 0xffdf, &chk_enable);
    }
    /*NRZ PRBS patterns*/
    else
    {
        /*0x161[10]*/
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x161, 0xfbff, &chk_enable);
    }

    rst_cnt_flag = (chk_enable ? 0 : 1);
    
    /*2. PRBS Check Enable*/
    ret= _ctc_tmm_dkit_misc_serdes_get_prbs_pat_by_mode(lchip, serdes_id, p_prbs->prbs_pattern, &pat_type);
    if(CLI_ERROR == ret)
    {
        return CLI_ERROR;
    }
    _ctc_tmm_dkit_misc_serdes_set_prbs_pat(lchip, p_prbs->serdes_id, 0, pat_type, TRUE);
    
    /*3. clear prbs error cnt*/
    if((!is_keep))
    {
        if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            _ctc_tmm_dkit_misc_serdes_ber_array_remove(serdes_id, &ber_mon.ber_array);
            
            if ((0 == ber_mon.ber_array.size) && (g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task))
            {
                g_usw_dkit_master[lchip]->monitor_task[task_id].task_end = 1;
                sal_task_destroy(g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task);
                g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task = NULL;

                if (g_usw_dkit_master[lchip]->monitor_task[task_id].para)
                {
                    mem_free(g_usw_dkit_master[lchip]->monitor_task[task_id].para);
                }
            }
                        
            ber_mon.dkit_tmm_prbs_err_cnt_mon[serdes_id] = 0;
            ber_mon.dkit_tmm_prbs_err_cnt_carry[serdes_id] = 0;
        }
        
        _ctc_tmm_dkit_misc_serdes_set_prbs_cnt_rst(lchip, serdes_id, &ber_mon);
    }
    else if(is_keep && rst_cnt_flag)
    {
        _ctc_tmm_dkit_misc_serdes_set_prbs_cnt_rst(lchip, serdes_id, &ber_mon);
        
        if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            ber_mon.dkit_tmm_prbs_err_cnt_mon[serdes_id] = 0;
            ber_mon.dkit_tmm_prbs_err_cnt_carry[serdes_id] = 0;

            _ctc_tmm_dkit_misc_serdes_ber_array_add(serdes_id, &ber_mon.ber_array);
            
            if ((0 != ber_mon.ber_array.size) && (NULL == g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task))
            {
                if (NULL == g_usw_dkit_master[lchip]->monitor_task[task_id].para)
                {
                    g_usw_dkit_master[lchip]->monitor_task[task_id].para = (ctc_dkit_monitor_para_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_monitor_para_t));
                    if (NULL == g_usw_dkit_master[lchip]->monitor_task[task_id].para)
                    {
                        return CLI_ERROR;
                    }
                }
                g_usw_dkit_master[lchip]->monitor_task[task_id].task_end = 0;
                sal_memcpy(g_usw_dkit_master[lchip]->monitor_task[task_id].para, &p_ber_mon , sizeof(ctc_dkit_tmm_serdes_ber_mon_t *));
                sal_sprintf(buffer, "TMM-Serdes-PRBS-BER-MON-%d", lchip);
                ret = sal_task_create(&g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task,
                                    buffer,
                                    SAL_DEF_TASK_STACK_SIZE,
                                    SAL_TASK_PRIO_DEF,
                                    _ctc_tmm_dkit_misc_serdes_monitor_prbs_ber_handler,
                                    g_usw_dkit_master[lchip]->monitor_task[task_id].para);

                if (CLI_ERROR == ret)
                {
                    return CLI_ERROR;
                }
            }
        }
    }

    /*4. PRBS Check Status Read*/
    /*4.1 delay before check*/
    if (delay)
    {
        sal_task_sleep(delay); 
    }
    else if(!is_keep)
    {
        sal_task_sleep(1000);
    }
    /*4.2 read error cnt*/
    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        err_cnt = _ctc_tmm_dkit_misc_serdes_get_prbs_cnt(lchip, serdes_id);

        if(0 != err_cnt)
        {
            *pass = FALSE;
        }
        else
        {
            *pass = TRUE;
        }

        p_prbs->error_count = err_cnt;
    }
    else
    {
        _ctc_tmm_dkit_misc_serdes_get_prbs_ber(lchip, serdes_id, &ber_mon, &ber);

        if(ber.ber_pow < (-6) || (( 0 == ber.ber_n) && (0 == ber.ber_farc) && (0 == ber.ber_pow)))
        {
            *pass = TRUE;
        }
        else
        {
            *pass = FALSE;
        }

        sal_memcpy(&p_prbs->ber, &ber, sizeof(ctc_tmm_dkit_misc_serdes_ber_t));
    }

    /*5. PRBS Check disable*/
    if(!is_keep)
    {
        _ctc_tmm_dkit_misc_serdes_set_prbs_pat(lchip, p_prbs->serdes_id, 0, pat_type, FALSE);     
    }
    
    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_do_serdes_prbs(uint8 lchip, ctc_dkit_tmm_serdes_ctl_prbs_t *p_prbs, bool* pass)
{
    int32 ret = CLI_SUCCESS;

    switch(p_prbs->oper)
    {
        case CTC_DKIT_SERDIS_CTL_ENABLE:
        case CTC_DKIT_SERDIS_CTL_DISABLE:
            ret = _ctc_tmm_dkit_misc_serdes_prbs_en(lchip, p_prbs);
            break;
        case CTC_DKIT_SERDIS_CTL_CHECK:
            ret = _ctc_tmm_dkit_misc_serdes_prbs_check(lchip, p_prbs, pass);
            break;
        default:
            CTC_DKIT_PRINT("Feature not supported!\n");
            break;
    }
    return ret;
}

STATIC void
_ctc_tmm_dkit_misc_serdes_monitor_handler(void* arg)
{
    ctc_dkit_tmm_serdes_ctl_prbs_t* p_prbs = (ctc_dkit_tmm_serdes_ctl_prbs_t*)arg;
    sal_time_t tv;
    char* p_time_str = NULL;
    uint8 lchip = p_prbs->lchip;
    uint16 serdes_id = 0;
    uint32 err_cnt = 0;
    uint16 time_count = 1000;
    sal_file_t p_file = NULL;
    uint16 pat_sel_val;
    uint16 data_low;
    uint16 data_high;
    uint8 nrz_prbs_pat[4] = {0, 2, 3, 4};/*"PRBS9", "PRBS15", "PRBS23", "PRBS31"*/ 
    uint8 pam4_prbs_pat[12] = {0, 1, 2, 4, 5, 6,  7, 8, 9, 10 , 11, 12};/*"PRBS9x", "PRBS13x", "PRBS15x", "PRBS31x"*/ 

    sal_time(&tv);
    p_time_str = sal_ctime(&tv);

    serdes_id = p_prbs->serdes_id;
    
    CTC_DKIT_PRINT("Serdes %d prbs check monitor begin, %s\n",serdes_id, p_time_str);
    
    if (0 != p_prbs->str[0])
    {
        p_file = sal_fopen(p_prbs->str, "wt");
        if (!p_file)
        {
            CTC_DKIT_PRINT("Open file %s fail!!!\n", p_prbs->str);
            return;
        }
        CTC_DKITS_PRINT_FILE(p_file, "Serdes %d prbs check moniter begin, %s\n", serdes_id, p_time_str);
        sal_fclose(p_file);
        p_file = NULL;
    }

    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        /*1. PRBS Mode Select*/
        for(pat_sel_val = 0; pat_sel_val < 4; pat_sel_val ++)
        {
            if(p_prbs->prbs_pattern == nrz_prbs_pat[pat_sel_val])
            {
                break;
            }
        }
        if(pat_sel_val == 4)
        {
            CTC_DKIT_PRINT("Pattern not supported!\n");
            return;
        }
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x161, 0xcfff, pat_sel_val);/*0x161[13:12]*/

        /*2. PRBS Check Enable*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x41, 0x7fff, 0);/*0x41[15]*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x161, 0xfbff, 1);/*0x161[10]*/

        /*reset error cnt*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_PRBS_CNT_RST_ADDR, NRZ_PRBS_CNT_RST_MASK, 1);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, NRZ_PRBS_CNT_RST_ADDR, NRZ_PRBS_CNT_RST_MASK, 0);

        /*3. PRBS Check Status Read*/
        err_cnt = 0;
        sal_task_sleep(1);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR, 0x0, &data_high);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR + 1, 0x0, &data_low);
        
        err_cnt = (data_high << 16) + data_low;
        
        while (1)
        {
            
            if (p_prbs->str[0])
            {
                p_file = sal_fopen(p_prbs->str, "a");
            }

            /*get systime*/
            sal_time(&tv);
            p_time_str = sal_ctime(&tv);
            if(0 != err_cnt)  //timeout, or error occur
            {
                CTC_DKITS_PRINT_FILE(p_file, "Serdes %d prbs check error, sync = %d, %s", serdes_id, !time_count, p_time_str);
                goto End;
            }
            else
            {
                CTC_DKITS_PRINT_FILE(p_file, "Serdes %d prbs check success, %s", serdes_id, p_time_str);
            }

            if (p_file)
            {
                sal_fclose(p_file);
                p_file = NULL;
            }
            sal_task_sleep(p_prbs->is_keep * 1000);

            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR, 0x0, &data_high);
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR + 1, 0x0, &data_low);

            err_cnt = (data_high << 16) + data_low;
        }
    }
    /*PAM4 Mode*/
    else
    {
        /*1. PRBS Mode Select*/
        for(pat_sel_val = 0; pat_sel_val < 12; pat_sel_val ++)
        {
            if(p_prbs->prbs_pattern == pam4_prbs_pat[pat_sel_val])
            {
                break;
            }
        }

        if(pat_sel_val == 12)
        {
            CTC_DKIT_PRINT("Pattern not supported!\n");
            return;
        }

        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TEST_PATT_CTRL_ADDR, TX_TEST_PATT_SEL_MASK, (pat_sel_val % 4));
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PRBS_MODE_SEL_ADDR_PAM4, PRBS_MODE_SEL_MASK_PAM4,  (pat_sel_val % 4));

        if(pat_sel_val >= 8)/*PRBSxQP*/
        {
            /*Tx Gray Code and Pre Code 0xaf[9:8]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xaf, 0xfcff, 3);
        }
        else if(pat_sel_val >= 4)/*PRBSxQ*/
        {
            /*Tx Gray Code and Pre Code 0xaf[9:8]*/
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0xaf, 0xfcff, 2);
        }

        /*2. PRBS Check Enable*/  
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x41, 0x7fff, 1);/*0x41[15]*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x43, 0xffef, 1);/*0x43[4]*/
        
        /*3. PRBS Check Status Read*/
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR, 0x0, &data_high);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR + 1, 0x0, &data_low);
        
        err_cnt = (data_high << 16) + data_low;

        while (1)
        {
            if (p_prbs->str[0])
            {
                p_file = sal_fopen(p_prbs->str, "a");
            }

            /*get systime*/
            sal_time(&tv);
            p_time_str = sal_ctime(&tv);
            if(0 != err_cnt)  //timeout, or error occur
            {
                CTC_DKITS_PRINT_FILE(p_file, "Serdes %d prbs check error, sync = %d, %s", serdes_id, !time_count, p_time_str);
                goto End;
            }
            else
            {
                CTC_DKITS_PRINT_FILE(p_file, "Serdes %d prbs check success, %s", serdes_id, p_time_str);
            }

            if (p_file)
            {
                sal_fclose(p_file);
                p_file = NULL;
            }
            
            sal_task_sleep(p_prbs->is_keep * 1000);

            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR, 0x0, &data_high);
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_PRBS_CNT_ADDR + 1, 0x0, &data_low);
            
            err_cnt = (data_high << 16) + data_low;
        }
        
    }

End:
    if (p_file)
    {
        sal_fclose(p_file);
        p_file = NULL;
    }
    
    return;
}

/********************************************************
 *TMM SerDes PRBS Mode
 *  0 : PRBS 9
 *  1 : PRBS13
 *  2 : PRBS15
 *  3 : PRBS23
 *  4 : PRBS31
 *  5 : PRBS9Q
 *  6 : PRBS13Q
 *  7 : PRBS15Q 
 *  8 : PRBS31Q
 *  9: PRBS9QP
 *  10: PRBS13QP
 *  11: PRBS15QP
 *  12: PRBS31QP
 *  13: Squareware(8081)
 *  14: PRBS1T(1010)
 */
STATIC int32
_ctc_tmm_dkit_misc_serdes_prbs_param_proc(uint8 lchip, ctc_dkit_tmm_serdes_ctl_prbs_t *p_prbs)
{
    uint8 prbs_pattern = 0;

    DKITS_PTR_VALID_CHECK(p_prbs);
    CTC_DKIT_LCHIP_CHECK(lchip);

    switch(p_prbs->prbs_pattern)
    {
        /*PRBS15+ & PRBS15-*/
        case 2:
        case 3:
            prbs_pattern = 2;/*PRBS15*/
            break;
        /*PRBS23+ & PRBS23-*/    
        case 4:
        case 5:
            prbs_pattern = 3;/*PRBS23*/
            break;
        /*PRBS31+ & PRBS31-*/
        case 6:
        case 7:
            prbs_pattern = 4;/*PRBS31*/
            break;
        /*PRBS9*/
        case 8:
            prbs_pattern = 0;/*PRBS9*/
            break;
        /*PRBS13*/
        case 12:
            prbs_pattern = 1;/*PRBS13*/
            break;
        /*PRBS9Q to PRBS31QP*/
        case 13:
        case 14:
        case 15:
        case 16:
        case 17:
        case 18:
        case 19:
        case 20:
            prbs_pattern = p_prbs->prbs_pattern - 8;/*PRBSxQ or PRBSxQP*/
            break;
        case 9:
            prbs_pattern = 13;/*Squareware(8081)*/
            break;
        case 11:
            prbs_pattern = 14;/*PRBS1T(1010)*/
            break;
        default:
            return CLI_ERROR;
    }
    
    p_prbs->prbs_pattern = prbs_pattern;
    
    return CLI_SUCCESS;
}


STATIC int32
_ctc_tmm_dkit_misc_serdes_prbs(uint8 lchip, void *p_data)
{
    int32 ret = CLI_SUCCESS;
    uint8 prbs_pattern_bak = 0;
    char* pattern[CTC_DIKT_TMM_PATTERN_NUM] = {"PRBS9", "PRBS13", "PRBS15", "PRBS23", "PRBS31",
                                               "PRBS9Q", "PRBS13Q", "PRBS15Q", "PRBS31Q", 
                                               "PRBS9QP", "PRBS13QP", "PRBS15QP", "PRBS31QP",
                                               "Squareware(8081)", "PRBS1T(1010)"};
    char* enable = NULL;
    bool pass = FALSE;
    sal_file_t p_file = NULL;
    uint8 task_id = CTC_DKIT_MONITOR_TASK_PRBS;
    uint32 cmd = 0;
    uint32 field_val = 0;
    uint16 serdes_id = 0;
    uint16 an_enable = 0;
    char buffer[SAL_TASK_MAX_NAME_LEN] = {0};
    ctc_dkit_tmm_serdes_ctl_prbs_t *p_prbs;

    p_prbs = (ctc_dkit_tmm_serdes_ctl_prbs_t *)p_data;

    DKITS_PTR_VALID_CHECK(p_data);
    CTC_DKIT_LCHIP_CHECK(lchip);

    serdes_id = p_prbs->serdes_id;
    prbs_pattern_bak = p_prbs->prbs_pattern;

    ret = _ctc_tmm_dkit_misc_serdes_prbs_param_proc(lchip, p_prbs);
    
    if (CLI_ERROR == ret)
    {
        CTC_DKIT_PRINT("Pattern not supported!\n");
        return CLI_ERROR;
    }

    cmd = DRV_IOR(OobFcReserved_t, OobFcReserved_reserved_f);
    DRV_FIELD_IOCTL(lchip, 0, cmd, &field_val);
    if (1 == field_val)
    {
        CTC_DKIT_PRINT("do prbs check, must close link monitor thread\n");
        return CLI_ERROR;
    }

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, AN_CONTROL_ADDR, 0xEFFF, &an_enable);
    if (an_enable)
    {
        CTC_DKIT_PRINT("do prbs check, must close ANLT.\n");
        return CLI_ERROR;
    }

    if (CTC_DKIT_SERDIS_CTL_MONITOR == p_prbs->oper)
    {
        if (NULL == g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task)
        {
            if (NULL == g_usw_dkit_master[lchip]->monitor_task[task_id].para)
            {
                g_usw_dkit_master[lchip]->monitor_task[task_id].para
                = (ctc_dkit_monitor_para_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_monitor_para_t));
                if (NULL == g_usw_dkit_master[lchip]->monitor_task[task_id].para)
                {
                    return CLI_ERROR;
                }
            }
            g_usw_dkit_master[lchip]->monitor_task[task_id].task_end = 0;
            sal_memcpy(g_usw_dkit_master[lchip]->monitor_task[task_id].para, p_prbs , sizeof(ctc_dkit_monitor_para_t));

            sal_sprintf(buffer, "SerdesPrbs-%d", lchip);
            ret = sal_task_create(&g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task,
                                  buffer,
                                  SAL_DEF_TASK_STACK_SIZE,
                                  SAL_TASK_PRIO_DEF,
                                  _ctc_tmm_dkit_misc_serdes_monitor_handler,
                                  g_usw_dkit_master[lchip]->monitor_task[task_id].para);
        }
        
        return CLI_SUCCESS;
    }
    else if (CTC_DKIT_SERDIS_CTL_DISABLE == p_prbs->oper)
    {
        if (g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task)
        {
            g_usw_dkit_master[lchip]->monitor_task[task_id].task_end = 1;
            sal_task_destroy(g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task);
            g_usw_dkit_master[lchip]->monitor_task[task_id].monitor_task = NULL;

            if (g_usw_dkit_master[lchip]->monitor_task[task_id].para)
            {
                mem_free(g_usw_dkit_master[lchip]->monitor_task[task_id].para);
            }
            return CLI_SUCCESS;
        }
    }

    ret = _ctc_tmm_dkit_misc_do_serdes_prbs(lchip, p_prbs, &pass);

    if(CLI_EOL == ret)
    {
        CTC_DKIT_PRINT("prbs is enable, need disable first.\n");
        return CLI_ERROR;
    }
    else if (CLI_ERROR == ret)
    {
        return CLI_ERROR;
    }

    if (0 != p_prbs->str[0])
    {
        p_file = sal_fopen(p_prbs->str, "wt");
        if (!p_file)
        {
            CTC_DKIT_PRINT("Open file %s fail!!!\n", p_prbs->str);
            return CLI_ERROR;
        }
    }
    
    if ((CTC_DKIT_SERDIS_CTL_ENABLE == p_prbs->oper)
           ||(CTC_DKIT_SERDIS_CTL_DISABLE == p_prbs->oper))
    {
        enable = (CTC_DKIT_SERDIS_CTL_ENABLE == p_prbs->oper)? "Yes":"No";
        CTC_DKITS_PRINT_FILE(p_file, "\n%-12s%-6s%-20s%-9s%-9s\n", "Serdes_ID", "Dir", "Pattern", "Enable", "Result");
        CTC_DKITS_PRINT_FILE(p_file, "--------------------------------------------\n");
        CTC_DKITS_PRINT_FILE(p_file, "%-12d%-6s%-20s%-9s%-9s\n", serdes_id, "TX", pattern[p_prbs->prbs_pattern], enable, "  -");
    }
    else if (CTC_DKIT_SERDIS_CTL_CHECK == p_prbs->oper)
    {
        enable = pass ? "Pass" : "Fail";

        if(CTC_DKIT_TMM_SERDES_PAM4_MODE != _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            CTC_DKITS_PRINT_FILE(p_file, "\n%-12s%-6s%-10s%-9s%-9s%-9s\n", "Serdes_ID", "Dir", "Pattern", "Enable", "Result", "Err_cnt");
            CTC_DKITS_PRINT_FILE(p_file, "-----------------------------------------------------\n");
            CTC_DKITS_PRINT_FILE(p_file, "%-12d%-6s%-10s%-9s%-9s%-9u\n", serdes_id, "RX", pattern[p_prbs->prbs_pattern], "  -", enable, p_prbs->error_count);
        }
        else
        {
            CTC_DKITS_PRINT_FILE(p_file, "\n%-12s%-6s%-10s%-9s%-9s%-9s\n", "Serdes_ID", "Dir", "Pattern", "Enable", "Result", "BER");
            CTC_DKITS_PRINT_FILE(p_file, "-----------------------------------------------------\n");
            CTC_DKITS_PRINT_FILE(p_file, "%-12d%-6s%-10s%-9s%-9s%d.%dE%d\n", serdes_id, "RX", pattern[p_prbs->prbs_pattern], "  -", enable, \
                                                                                                p_prbs->ber.ber_n, p_prbs->ber.ber_farc, p_prbs->ber.ber_pow);
        }
    }
    if (p_file)
    {
        sal_fclose(p_file);
    }

    p_prbs->prbs_pattern = prbs_pattern_bak;

    return CLI_SUCCESS;
}

STATIC uint32
_ctc_tmm_dkit_misc_serdes_get_eye(uint8 lchip, uint16 serdes_id, uint8 fw_is_running, uint16 *dacq)
{
    uint16 dacq_reg_val;
    uint16 eye_reg_val;
    uint32 eye_mV = 0;

    /*NRZ Mode Eye Margin*/
    if(CTC_DKIT_TMM_SERDES_PAM4_MODE != _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DAC_SEL_ADDR_NRZ, DAC_SEL_MASK_NRZ, &dacq_reg_val);

        /*when firmware isn't running, get eye data from hardward register*/
        if(0 == fw_is_running)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, EYE_READ_ADDR_NRZ, EYE_READ_MASK_NRZ, &eye_reg_val);
        }
        /*when firmware is running, get eye data by dump*/
        else
        {  
            _ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, 0x9, 4, &eye_reg_val);
            _ctc_tmm_dkit_misc_serdes_fw_read_s16(lchip, serdes_id, 0, &eye_reg_val);
        }

        /*NRZ Eye Formula*/
        if(eye_reg_val > 0)
        {
            eye_mV = (eye_reg_val * 10000 / 2048) * (200 + (50 * dacq_reg_val));
        }
    }
    /*PAM4 Mode Eye Margin*/
    else
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DAC_SEL_ADDR_PAM4, DAC_SEL_MASK_PAM4, &dacq_reg_val);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, EYE_READ_ADDR_PAM4, EYE_READ_MASK_PAM4, &eye_reg_val);

        if(eye_reg_val > 0xFFF)
        {
            sal_task_sleep(500);
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, EYE_READ_ADDR_PAM4, EYE_READ_MASK_PAM4, &eye_reg_val);
        }

        if(eye_reg_val > 0)
        {
            eye_mV = (eye_reg_val * 10000 / 2048) * (100 + (50 * dacq_reg_val));
        }

        if(eye_mV > 300)
        {
            eye_mV = 1 * 10000;
        }
    }

    eye_mV = eye_mV / 10000;

    if(dacq != NULL)
    {
        *dacq = dacq_reg_val;
    }

    return eye_mV;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_get_eye3(uint8 lchip, uint16 serdes_id, uint8 fw_is_running, uint32 *eye_margin, uint16 *dacq)
{
    uint32 eye_mV[3] = {0,0,0};
    uint8 eye_index = 0, y = 0;
    uint16 sel;
    int16 plus_margin;
    int16 minus_margin;
    uint16 dacq_reg_val;
    uint16 diff;
    uint16 data;
    uint16 result = 0xffff;

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DAC_SEL_ADDR_PAM4, DAC_SEL_MASK_PAM4, &dacq_reg_val);

    for(eye_index = 0; eye_index < 3; eye_index ++)
    {
        /*when firmware isn't running, get eye data from hardward register*/
        if(0 == fw_is_running)
        {
            result = 0xffff;
            for(y = 0; y < 4; y ++)
            {
                sel = 3*y + eye_index;
                _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_DFE_SEL_ADDR, 0xf0ff, sel);
                _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_DFE_SEL_ADDR, 0x0fff, sel);
            
                _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, EYE_MARGIN_ADDR, EYE_PLUS_MARGIN_MASK, &data);
                plus_margin = data;
                if(plus_margin > 0x7ff)
                {
                    plus_margin = (plus_margin > 0x1000) ? (plus_margin - 0x1000) : ((0x1000 - plus_margin)*(-1));
                }
                _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, EYE_MARGIN_ADDR, EYE_MINUS_MARGIN_UPPER_MASK, &data);
                minus_margin = data;
                _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, EYE_MARGIN_ADDR2, EYE_MINUS_MARGIN_LOWER_MASK, &data);
                minus_margin = (minus_margin << 8) + data;
            
                if(minus_margin > 0x7ff)
                {
                    minus_margin = (minus_margin > 0x1000) ? (minus_margin - 0x1000) : ((0x1000 - minus_margin)*(-1));
                }
            
                diff = plus_margin - minus_margin;
                if(diff < result) 
                {
                    result = diff;
                }
            }

            eye_mV[eye_index] = (result * 10000 / 2048) * (100 + (50 * dacq_reg_val));
            eye_mV[eye_index] = eye_mV[eye_index] / 10000;
        }
        /*when firmware is running, get eye data by dump*/
        else
        {
            _ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, 0xa, 4, &data);
            _ctc_tmm_dkit_misc_serdes_fw_read_s16(lchip, serdes_id, eye_index, &result);
            eye_mV[eye_index] = result;
        }
    }

    if(dacq != NULL)
    {
        *dacq = dacq_reg_val;
    }

    sal_memcpy(eye_margin, eye_mV, sizeof(uint32)*3);

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_eye_mon_nrz_plot(uint8 lchip, uint16 serdes_id)
{
#define EYE_MON_VERT_SIZE_SIDE 48
#define EYE_MON_PHASE_RANGE 16
    uint16 eye_mon_data_start_addr = 0x9f00;
    int16 pindex = 0;
    int16 phase = 0;
    int16 margin = 0;
    uint16 status = 0;
    uint16 data = 0, extent = 0;
    int16 index = 0, m = 0;
    uint16 vert_size_full = 0;
    uint16** eye_mon_data = NULL;
    uint16 i = 0;
    //char file_name[64];
    //sal_file_t p_file = NULL;

    vert_size_full = EYE_MON_VERT_SIZE_SIDE*2 + 1;

    eye_mon_data = (uint16**)mem_malloc(MEM_DMPS_MODULE, (EYE_MON_VERT_SIZE_SIDE*2 + 1) * sizeof(uint16*));
    for(i = 0; i < (EYE_MON_VERT_SIZE_SIDE*2 + 1); i++)
    {
        eye_mon_data[i] = (uint16*)mem_malloc(MEM_DMPS_MODULE, (EYE_MON_PHASE_RANGE*2 + 1) * sizeof(uint16));
        sal_memset(eye_mon_data[i], 0 , (EYE_MON_PHASE_RANGE*2 + 1) * sizeof(uint16));
    }

    for(phase = (-1)*EYE_MON_PHASE_RANGE; phase < EYE_MON_PHASE_RANGE + 1; phase ++)
    {
        pindex = phase + EYE_MON_PHASE_RANGE;
        
        for(margin = (-1)*EYE_MON_VERT_SIZE_SIDE; margin < EYE_MON_VERT_SIZE_SIDE + 1; margin += 16)
        {
            _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, FW_EYEMON_READ_CMD | (phase & 0xff), margin, CTC_DKIT_SERDES_PARAM_NONE, &status);

            if(((status >> 8) & 0xf) != 2)
            {
                for(index = 0; index < 16; index ++)
                {
                    m = margin + index + EYE_MON_VERT_SIZE_SIDE;
                    if(m < vert_size_full)
                    {
                        eye_mon_data[m][pindex] = 0;
                    }
                }
            }
            else
            {
                for(index = 0; index < 16; index ++)
                {
                    m = margin + index + EYE_MON_VERT_SIZE_SIDE;
                    if(m < vert_size_full)
                    {
                        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, eye_mon_data_start_addr + index, 0x0, &data);
                        eye_mon_data[m][pindex] = data;
                    }
                }
            }
        }
    }
    
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x9816, 0x0, &extent);

    /*to file*/
#if 0    
    sal_sprintf(file_name, "serdes_%d_NRZ_eye_mon_data.txt", serdes_id);
    p_file = sal_fopen(file_name, "w");
    if (!p_file)
    {
        CTC_DKIT_PRINT("Open file %s fail!!!\n", "eye_mon_data.txt");
        return CLI_SUCCESS;
    }
    CTC_DKITS_PRINT_FILE(p_file, "serdes : %d mode : NRZ\nEye Data:\n", serdes_id);
    CTC_DKITS_PRINT_FILE(p_file, "extent = %4d\n", extent);
    CTC_DKITS_PRINT_FILE(p_file, "\neye_data = [\n");

    for(margin = 0; margin < vert_size_full; margin ++)
    {
        for(pindex =0; pindex < EYE_MON_PHASE_RANGE*2 + 1; pindex ++)
        {
            CTC_DKITS_PRINT_FILE(p_file, "%u, ", eye_mon_data[margin][pindex]);
        }
        CTC_DKITS_PRINT_FILE(p_file, "\n");
    }
    CTC_DKITS_PRINT_FILE(p_file, "\n]\n");
    
    sal_fclose(p_file);

    CTC_DKIT_PRINT("Result In File : %s.\n", file_name);
#endif
    CTC_DKIT_PRINT("serdes : %d mode : NRZ\nEye Data:\n", serdes_id);
    CTC_DKIT_PRINT("extent = %4d\n", extent);
    CTC_DKIT_PRINT("\neye_data = [\n");

    for(margin = 0; margin < vert_size_full; margin ++)
    {
        for(pindex =0; pindex < EYE_MON_PHASE_RANGE*2 + 1; pindex ++)
        {
            CTC_DKIT_PRINT("%-3u, ", eye_mon_data[margin][pindex]);
        }
        CTC_DKIT_PRINT("\n");
    }
    CTC_DKIT_PRINT("\n]\n");

    for(i = 0; i < (EYE_MON_PHASE_RANGE*2 + 1); i++)
    {
        mem_free(eye_mon_data[i]);
    }
    mem_free(eye_mon_data);

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_eye_mon_pam4_plot(uint8 lchip, uint16 serdes_id)
{
#define EYE_MON_PHASE_RANGE 16

    uint16 eye_mon_phase_addr = 0x9815;
    uint16 eye_mon_margin_mult_addr = 0x9816;
    uint16 eye_mon_data_start_addr = 0x9f00;
    int16 pindex = 0;
    int16 phase = 0;
    int16 margin = 0;
    uint16 status = 0;
    uint16 data = 0, extent = 0;
    int16 index = 0, m = 0;
    char file_name[64];
    sal_file_t p_file = NULL;

    uint16** eye_mon_data = NULL;
    uint16 i = 0;

    eye_mon_data = (uint16**)mem_malloc(MEM_DMPS_MODULE, 127 * sizeof(uint16*));
    for(i = 0; i < 127; i++)
    {
        eye_mon_data[i] = (uint16*)mem_malloc(MEM_DMPS_MODULE, (EYE_MON_PHASE_RANGE*2 + 1) * sizeof(uint16));
        sal_memset(eye_mon_data[i], 0 , (EYE_MON_PHASE_RANGE*2 + 1) * sizeof(uint16));
    }

    for(phase = (-1)*EYE_MON_PHASE_RANGE; phase < EYE_MON_PHASE_RANGE + 1; phase ++)
    {
        pindex = phase + EYE_MON_PHASE_RANGE;

        for(margin = -63; margin < 64; margin += 16)
        {
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, eye_mon_margin_mult_addr, 0x0, margin & 0xffff);
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, eye_mon_phase_addr, 0x0, (phase & 0xff) | 0x3000);

            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, eye_mon_phase_addr, 0x0, &data);

            while((data >> 12) != 0)
            {
                _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, eye_mon_phase_addr, 0x0, &data);
            }

            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, eye_mon_phase_addr, 0x0, &status);

            if(((status >> 8) & 0xf) != 2)
            {
                for(index = 0; index < 16; index ++)
                {
                        m = margin + index;
                        if(m < 64)
                        {
                            eye_mon_data[63 + m][pindex] = 0;
                        }
                    }
                }
                else
                {
                    for(index = 0; index < 16; index ++)
                    {
                        m = margin + index;
                        if(m < 64)
                        {
                            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, eye_mon_data_start_addr + index, 0x0, &data);
                            eye_mon_data[63 + m][pindex] = data;
                        }
                }
            }
        }
    }

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, eye_mon_data_start_addr + index, 0x0, &extent);

    /*to file*/
    sal_sprintf(file_name, "serdes_%d_PAM4_eye_mon_data.txt", serdes_id);
    p_file = sal_fopen(file_name, "w");
    if (!p_file)
    {
        CTC_DKIT_PRINT("Open file %s fail!!!\n", "eye_mon_data.txt");

        for(i = 0; i < (EYE_MON_PHASE_RANGE*2 + 1); i++)
        {
            mem_free(eye_mon_data[i]);
        }
        mem_free(eye_mon_data);

        return CLI_SUCCESS;
    }
#if 0    
    CTC_DKITS_PRINT_FILE(p_file, "serdes : %d mode : PAM4\nEye Data:\n", serdes_id);
    CTC_DKITS_PRINT_FILE(p_file, "extent = %4d \n", extent);
    CTC_DKITS_PRINT_FILE(p_file, "\neye_data = [\n");

    for(margin = 0; margin < (63*2 + 1); margin ++)
    {
        for(pindex =0; pindex < EYE_MON_PHASE_RANGE*2 + 1; pindex ++)
        {
            CTC_DKITS_PRINT_FILE(p_file, "%u, ", eye_mon_data[margin][pindex]);
        }
        CTC_DKITS_PRINT_FILE(p_file, "\n");
    }
    CTC_DKITS_PRINT_FILE(p_file, "\n]\n");
    sal_fclose(p_file);

    CTC_DKIT_PRINT("Result In File : %s.\n", file_name);
#endif

    CTC_DKIT_PRINT("serdes : %d mode : PAM4\nEye Data:\n", serdes_id);
    CTC_DKIT_PRINT("extent = %4d\n", extent);
    CTC_DKIT_PRINT("\neye_data = [\n");

    for(margin = 0; margin < 127; margin ++)
    {
        for(pindex =0; pindex < EYE_MON_PHASE_RANGE*2 + 1; pindex ++)
        {
            CTC_DKIT_PRINT("%-3u, ", eye_mon_data[margin][pindex]);
        }
        CTC_DKIT_PRINT("\n");
    }
    
    CTC_DKIT_PRINT("\n]\n");

    for(i = 0; i < (EYE_MON_PHASE_RANGE*2 + 1); i++)
    {
        mem_free(eye_mon_data[i]);
    }
    mem_free(eye_mon_data);
    sal_fclose(p_file);

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_eye_mon_plot(uint8 lchip, uint16 serdes_id)
{
    uint32 data_rate = 0;
    
    _ctc_tmm_dkit_misc_serdes_get_datarate(lchip, serdes_id, &data_rate);

    if(data_rate <= 500000)
    {
        CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
        CTC_DKIT_PRINT(" Current mode don't support this feature!\n");
        return CLI_ERROR;
    }
    _ctc_tmm_dkit_misc_serdes_set_eye_mon_collect(lchip, serdes_id, 7, CTC_DKIT_TMM_SERDES_EYE_MON_COLLECT_OPTION_NONE);
    
    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_serdes_eye_mon_nrz_plot(lchip, serdes_id);
    }
    else
    {
        _ctc_tmm_dkit_misc_serdes_eye_mon_pam4_plot(lchip, serdes_id);   
    }

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_eye(uint8 lchip, void *p_data)
{
    uint8 fw_is_running = 0;
    uint16 serdes_id = 0;
    uint32 index = 0, n = 0;
    uint32 times = 0;
    uint32 eye_margin = 0;
    uint32 eye_min = 0xffff;
    uint32 eye_max = 0;
    uint32 eye3_margin[3] = {0,0,0};
    uint32 eye3_min[3] = {0xffff, 0xffff, 0xffff};
    uint32 eye3_max[3] = {0,0,0};
    uint32 eye3_sum[3] = {0,0,0};
    uint32 sum = 0;
    uint16 dacq = 0;
    uint16 dacq_min = 0xffff;
    uint16 dacq_max = 0;
    uint16 dacq_sum = 0;

    ctc_dkit_tmm_serdes_ctl_eye_t *p_eye;

    DKITS_PTR_VALID_CHECK(p_data);
    CTC_DKIT_LCHIP_CHECK(lchip);

    p_eye = (ctc_dkit_tmm_serdes_ctl_eye_t *)p_data;

    serdes_id= p_eye->serdes_id;

    times = p_eye->read_times;

    if(0 == times)
    {
        times = 10;
    }

    fw_is_running = _ctc_tmm_dkit_misc_serdes_is_fw_running(lchip, serdes_id);

    if((CTC_DKIT_SERDIS_EYE_HEIGHT == p_eye->eye_type) || (CTC_DKIT_SERDIS_EYE_ALL == p_eye->eye_type))
    {
        if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
                CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
                CTC_DKIT_PRINT(" %-10s%-10s%-10s\n", "No.", "EyeOpen", "DACQ");
                CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
                for(index = 0; index < times; index ++)
                {
                    eye_margin = _ctc_tmm_dkit_misc_serdes_get_eye(lchip, serdes_id, fw_is_running, &dacq);
                    sum += eye_margin;
                    dacq_sum += dacq;

                    eye_max = (eye_margin > eye_max ? eye_margin : eye_max);
                    eye_min = (eye_margin < eye_min ? eye_margin : eye_min);

                    dacq_max = (dacq > dacq_max ? dacq : dacq_max);
                    dacq_min = (dacq < dacq_min ? dacq : dacq_min);

                    CTC_DKIT_PRINT(" %-10d%-10d%-10d\n", index + 1, eye_margin, dacq);
                }

                CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
                CTC_DKIT_PRINT(" %-10s%-10d%-10d\n","Min", eye_min, dacq_min);
                CTC_DKIT_PRINT(" %-10s%-10d%-10d\n","Max", eye_max, dacq_max);
                CTC_DKIT_PRINT(" %-10s%-10d%-10d\n","Avg", (sum /times), (dacq_sum /times));
        }
        else
        {
            CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
            CTC_DKIT_PRINT(" %-10s  %-10s  %-10s  %-10s  %-10s\n", "No.", "Eye1_Open","Eye2_Open","Eye3_Open", "DACQ");
            CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
            for(index = 0; index < times; index ++)
            {
                _ctc_tmm_dkit_misc_serdes_get_eye3(lchip, serdes_id, fw_is_running, eye3_margin, &dacq);
                
                dacq_sum += dacq;
                dacq_max = (dacq > dacq_max ? dacq : dacq_max);
                dacq_min = (dacq < dacq_min ? dacq : dacq_min);

                for(n = 0; n < 3; n ++)
                {
                    eye3_sum[n] += eye3_margin[n];
                    eye3_max[n] = (eye3_margin[n] > eye3_max[n] ? eye3_margin[n] : eye3_max[n]);
                    eye3_min[n] = (eye3_margin[n] < eye3_min[n] ? eye3_margin[n] : eye3_min[n]);
                }

                CTC_DKIT_PRINT(" %-10d  %-10d  %-10d  %-10d  %-10d\n", index + 1, eye3_margin[0], eye3_margin[1], eye3_margin[2], dacq);
            }

            CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
            CTC_DKIT_PRINT(" %-10s  %-10d  %-10d  %-10d  %-10d\n","Min", eye3_min[0], eye3_min[1], eye3_min[2], dacq_min);
            CTC_DKIT_PRINT(" %-10s  %-10d  %-10d  %-10d  %-10d\n", "Max", eye3_max[0], eye3_max[1], eye3_max[2], dacq_max);
            CTC_DKIT_PRINT(" %-10s  %-10d  %-10d  %-10d  %-10d\n","Avg", eye3_sum[0] / times, eye3_sum[1] / times, eye3_sum[2] / times, dacq_sum /times);
        }
    }

    if((CTC_DKIT_SERDIS_EYE_WIDTH == p_eye->eye_type) || (CTC_DKIT_SERDIS_EYE_ALL == p_eye->eye_type))
    {
        CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
        CTC_DKIT_PRINT(" Feature EYE WIDTH not support!\n");
    } 

    if(CTC_DKIT_SERDIS_EYE_WIDTH_SLOW == p_eye->eye_type)
    {
        _ctc_tmm_dkit_misc_serdes_eye_mon_plot(lchip, serdes_id);
    }
    
    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_set_tx_taps(uint8 lchip, ctc_tmm_dkit_misc_serdes_tx_taps_param_t *p_data)
{
    uint16 data = 0;
    int8 taps_data = 0;
    uint16 scale_data = 0;
    uint8 serdes_id = 0;
    uint8 index = 0;
    uint16 reg_list[5][2] = {
            /* address        mask       */
            {TX_PRE2_ADDR,  TX_PRE2_MASK},
            {TX_PRE1_ADDR,  TX_PRE1_MASK},
            {TX_MAIN_ADDR,  TX_MAIN_MASK},
            {TX_POST1_ADDR, TX_POST1_MASK},
            {TX_POST2_ADDR, TX_POST2_MASK}};

    uint16 scale_mask[5] = {
             TX_PRE2_SCALE_MASK,
             TX_PRE1_SCALE_MASK,
             TX_MAIN_SCALE_MASK,
             TX_POST1_SCALE_MASK,
             TX_POST2_SCALE_MASK};

    serdes_id = p_data->serdes_id;

    for(index = 0; index < 5; index ++)
    {   
        if(0 == (p_data->taps_param[index] % 2))
        {
            taps_data = p_data->taps_param[index] / 2;
            scale_data = 1;
        }
        else
        {
            taps_data = p_data->taps_param[index];
            scale_data = 0;
        }
        
        data = CTC_DIKT_TMM_SERDES_TWOS_TO_INT(taps_data, 8);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip,serdes_id, CTC_DKIT_SERDES_ALL, reg_list[index][0], reg_list[index][1], data);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip,serdes_id, CTC_DKIT_SERDES_ALL, TX_TAPS_SCALE_ADDR, scale_mask[index], scale_data);
    }

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_get_tx_taps(uint8 lchip, ctc_tmm_dkit_misc_serdes_tx_taps_param_t *p_data)
{
    uint16 data = 0;
    uint8 serdes_id = 0;
    uint8 index = 0;
    uint16 scale_data = 0;
#ifndef EMULATION_ENV
    uint8 bit_width = 0;
#endif
    uint16 *p_reg = NULL;
    uint16 reg_list1[5][2] = {
            /* address         mask       */
            {TX_PRE2_ADDR,   TX_PRE2_MASK},
            {TX_PRE1_ADDR,   TX_PRE1_MASK},
            {TX_MAIN_ADDR,   TX_MAIN_MASK},
            {TX_POST1_ADDR,  TX_POST1_MASK},
            {TX_POST2_ADDR,  TX_POST2_MASK}};

    uint16 reg_list2[5][2] = {
             /* address            mask       */
            {TX_PRE2_ADDR,       TX_PRE2_MASK},
            {KR_SM_COEF_ADDR,    KR_SM_COEF_1_MASK},
            {KR_SM_COEF_ADDR,    KR_SM_COEF_0_MASK},
            {KR_SM_COEF_M_ADDR, KR_SM_COEF_M1_MASK},
            {KR_SM_COEF_M_ADDR, KR_SM_COEF_M2_MASK}};

    uint16 scale_mask[5] = {
             TX_PRE2_SCALE_MASK,
             TX_PRE1_SCALE_MASK,
             TX_MAIN_SCALE_MASK,
             TX_POST1_SCALE_MASK,
             TX_POST2_SCALE_MASK};

    serdes_id = p_data->serdes_id;

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, reg_list1[0][0], reg_list1[0][1], &data);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TAPS_SCALE_ADDR, scale_mask[0], &scale_data);
#ifndef EMULATION_ENV    
    p_data->taps_param[0] = CTC_DIKT_TMM_SERDES_INT_TO_TOWS(data, 8);
    p_data->taps_param[0] = (scale_data == 0 ? p_data->taps_param[0] : (p_data->taps_param[0] * 2));
#endif

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, KR_SM_COEF_SEL_ADDR, KR_SM_COEF_SEL_MASK, &data);

    if(data)
    {
        /*In KR mode, it's [unused, pre2, pre1, main, post]*/
        p_reg = &reg_list2[0][0];
#ifndef EMULATION_ENV
        bit_width = 6;
#endif
    }
    else
    {
        p_reg = &reg_list1[0][0];
#ifndef EMULATION_ENV
        bit_width = 8;
#endif
    }

    for(index = 1; index < 5; index ++)
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, *((p_reg + index * 2) + 0), *((p_reg + index * 2) + 1), &data);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, TX_TAPS_SCALE_ADDR, scale_mask[index], &scale_data);
#ifndef EMULATION_ENV
        p_data->taps_param[index] = CTC_DIKT_TMM_SERDES_INT_TO_TOWS(data, bit_width);
        p_data->taps_param[index] = (scale_data == 0 ? p_data->taps_param[index] : (p_data->taps_param[index] * 2));
#endif
    }

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_ffe_scan(uint8 lchip, void *p_data)
{
    CTC_DKIT_PRINT(" Feature not support!\n");
    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_polr_check(uint8 lchip, void *p_data)
{
    CTC_DKIT_PRINT(" Feature not support!\n");
    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_dfe_set_en(uint8 lchip, void *p_data)
{
    CTC_DKIT_PRINT(" Feature not support!\n");
    return CLI_SUCCESS;
}

int32 
_ctc_tmm_dkit_misc_serdes_get_ths_fw(uint8 lchip, uint8 serdes_id, int16 *p_list)
{
    uint8 index = 0;
    uint16 data;
    int16 tmp_val = 0;
    uint16 cmd;
    uint16 result = 0;

    cmd = FW_DEBUG_CMD + ((0xA & 0xf) << 4);

    _ctc_tmm_dkit_misc_serdes_fw_cmd(lchip, serdes_id, cmd, 1, 0xb, &result);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_CMD_DETAIL_ADDR, 0x0, &result);
    
    for(index=0; index< 12; index ++)
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x9f00+index, 0x0, &data);
        if((data & 0x8000) != 0)
        {
            tmp_val = (-1) * (0x10000 - data);
        }
        else
        {
            tmp_val = data;
        }
        p_list[index] = (int)(tmp_val / 32);
    }

    return CLI_SUCCESS;
}

int32 
_ctc_tmm_dkit_misc_serdes_get_pam4_dfe(uint8 lchip, ctc_dkit_tmm_serdes_ctl_dfe_t *p_data)
{
    int32 ths_list[12];
    int16 ths_list_temp[12];
    uint8 index = 0;
    uint16 serdes_id = 0;

    serdes_id = p_data->serdes_id;
    if(_ctc_tmm_dkit_misc_is_fw_loaded(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_serdes_get_ths_fw(lchip, serdes_id, ths_list_temp);

        for(index = 0; index < 12; index ++)
        {
            ths_list[index] = ths_list_temp[index] * 1000000 / 64;
        }
    }
    else
    {
        CTC_DKIT_PRINT("Firmware of SerDes %d is running ?\n", serdes_id);
        return CLI_ERROR;
    }

    p_data->taps_pam4[0] = (-3 * 100 / 16)*((ths_list[0]-ths_list[2])+(ths_list[3]-ths_list[5])+(ths_list[6]-ths_list[8])+(ths_list[9]-ths_list[11]));
    p_data->taps_pam4[1] = (-3 * 100 / 20)*((ths_list[0]+ths_list[1]+ths_list[2]-ths_list[9]-ths_list[10]-ths_list[11])+(ths_list[3]+ths_list[4]+ths_list[5]-ths_list[6]-ths_list[7]-ths_list[8])/3);

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_get_nrz_dfe(uint8 lchip, ctc_dkit_tmm_serdes_ctl_dfe_t *p_data)
{
    uint16 data;
    uint16 serdes_id = 0;

    serdes_id = p_data->serdes_id;

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DFE_F1_ADDR_NRZ, DFE_F1_MASK, &data);
    p_data->taps[0] = CTC_DIKT_TMM_SERDES_INT_TO_TOWS(data,7);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DFE_F2_ADDR_NRZ, DFE_F2_MASK, &data);
    p_data->taps[1] = CTC_DIKT_TMM_SERDES_INT_TO_TOWS(data,7);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DFE_F3_ADDR, DFE_F3_MASK, &data);
    p_data->taps[2] = CTC_DIKT_TMM_SERDES_INT_TO_TOWS(data,7);

    /*delta*/
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DFE_DELTA_ADDR, DFE_DELTA_MASK, &data);
    p_data->delta = data;

    return CLI_SUCCESS;
}


STATIC int32
_ctc_tmm_dkit_misc_serdes_dfe_get_val(uint8 lchip, void *p_data)
{
    uint16 serdes_id = 0;
    ctc_dkit_tmm_serdes_ctl_dfe_t *p_dfe;

    p_dfe = (ctc_dkit_tmm_serdes_ctl_dfe_t *)p_data;

    serdes_id = p_dfe->serdes_id;
    
    if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
       _ctc_tmm_dkit_misc_serdes_get_pam4_dfe(lchip, p_dfe);
    }
    else
    {
        _ctc_tmm_dkit_misc_serdes_get_nrz_dfe(lchip, p_dfe);
    }
    
    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_show_dfe(uint8 lchip, void *p_data)
{
    uint16 serdes_id = 0;
    int32 tap_1_pam4_abs = 0;
    int32 tap_2_pam4_abs = 0;
    ctc_dkit_tmm_serdes_ctl_dfe_t *p_dfe;

    p_dfe = (ctc_dkit_tmm_serdes_ctl_dfe_t *)p_data;

    serdes_id = p_dfe->serdes_id;

    _ctc_tmm_dkit_misc_serdes_dfe_get_val(lchip, p_data);

    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
        CTC_DKIT_PRINT(" serdes_id %d DFE status\n", serdes_id);
        CTC_DKIT_PRINT(" Tap1 val: %d\n", p_dfe->taps[0]);
        CTC_DKIT_PRINT(" Tap2 val: %d\n", p_dfe->taps[1]);
        CTC_DKIT_PRINT(" Tap3 val: %d\n", p_dfe->taps[2]);
        CTC_DKIT_PRINT(" Delta val: %d\n", p_dfe->taps[3]);
        CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
    }
    else
    {
        tap_1_pam4_abs = ((p_dfe->taps_pam4[0] > 0) ? p_dfe->taps_pam4[0] : (0 - p_dfe->taps_pam4[0]));
        tap_2_pam4_abs = ((p_dfe->taps_pam4[1] > 0) ? p_dfe->taps_pam4[1] : (0 - p_dfe->taps_pam4[1]));
        
        CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
        CTC_DKIT_PRINT(" serdes_id %d DFE status\n", serdes_id);
        CTC_DKIT_PRINT(" DFE status\n");
        CTC_DKIT_PRINT(" Tap1 val: %s%d.%08d\n", (p_dfe->taps_pam4[0] >= 0 ? "" : "-"), (tap_1_pam4_abs / 100000000), (tap_1_pam4_abs % 100000000));
        CTC_DKIT_PRINT(" Tap2 val: %s%d.%08d\n", (p_dfe->taps_pam4[1] >= 0 ? "" : "-"), (tap_2_pam4_abs / 100000000), (tap_2_pam4_abs % 100000000));
        CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
    }

    return CLI_SUCCESS;
}


int32 
_ctc_tmm_dkit_misc_serdes_lane_reset_toggle(uint8 lchip, uint8 serdes_id,uint32 time_ms)
{
    if(CTC_DKIT_TMM_SERDES_PAM4_MODE != _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, LANE_RESET_ADDR_NRZ, LANE_RESET_MASK_NRZ, 1);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_CONTINUE_ADDR_NRZ, SM_CTRL_CONTINUE_MASK_NRZ, 0);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_CONTINUE_ADDR_NRZ, SM_CTRL_CONTINUE_MASK_NRZ, 1);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_CONTINUE_ADDR_NRZ, SM_CTRL_CONTINUE_MASK_NRZ, 0);
        sal_task_sleep(time_ms);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, LANE_RESET_ADDR_NRZ, LANE_RESET_MASK_NRZ, 0);
    }
    else
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, LANE_RESET_ADDR_PAM4, LANE_RESET_MASK_PAM4, 1);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_CONTINUE_ADDR_PAM4, SM_CTRL_CONTINUE_MASK_PAM4, 0);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_CONTINUE_ADDR_PAM4, SM_CTRL_CONTINUE_MASK_PAM4, 1);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_CONTINUE_ADDR_PAM4, SM_CTRL_CONTINUE_MASK_PAM4, 0);
        sal_task_sleep(time_ms);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, LANE_RESET_ADDR_PAM4, LANE_RESET_MASK_PAM4, 0);
    }

    return CLI_SUCCESS;
}

uint8
_ctc_tmm_dkit_misc_serdes_get_tuning_done_status(uint8 lchip, uint8 serdes_id)
{
    uint16 data = 0;
    uint8 stat = 0;
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_TUNING_STATUS_ADDR, FW_TUNING_STATUS_DONE_MASK, &data);

    stat = (uint8)data;
    
    return stat;
}

int32 
_ctc_tmm_dkit_misc_serdes_wait_tuning_done(uint8 lchip, uint8 serdes_id)
{
    uint8 stat;
    uint16 cnt = 0;
    
    if((0 == _ctc_tmm_dkit_misc_is_fw_loaded(lchip, serdes_id)) && (0 == _ctc_tmm_dkit_misc_serdes_is_fw_running(lchip, serdes_id)))
    {
        return 1;
    }

    sal_task_sleep(20);
    stat = _ctc_tmm_dkit_misc_serdes_get_tuning_done_status(lchip, serdes_id);

    while(stat == 0)
    {
        cnt += 1;
        if(cnt >= 20000)
        {
            break;
        }
        
        stat = _ctc_tmm_dkit_misc_serdes_get_tuning_done_status(lchip, serdes_id);
    }

    return stat;
}

STATIC int32
_ctc_tmm_dkit_msic_serdes_get_fw_status(uint8 lchip, uint8 serdes_id)
{
    uint16 data = 0;
    uint8 load_stat = 0;
    uint8 running_stat = 0;
    uint16 val_0 = 0, val_1 = 0;

    /*Load Status*/
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x9814, 0x0, &data);
    if(0 == data)
    {
        load_stat = 0;
    }
    else
    {
        load_stat = 1;
    }

    /*Running Status. check the watchdog counter to see if FW is incrementing it*/
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_WATCHDOG_TIMER_ADDR, 0x0, &val_0);
    sal_task_sleep(1800); 
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_WATCHDOG_TIMER_ADDR, 0x0, &val_1);

    if(val_1 != val_0)  
    {
        running_stat = 1;  
    }
    else
    {
        running_stat = 0;  
    }

    CTC_DKIT_PRINT("---------SerDes %d FirmWare Status---------\n", serdes_id);
    CTC_DKIT_PRINT("%-20s : %10s\n","Load Status", (load_stat ? "Success" : "FAILURE"));
    CTC_DKIT_PRINT("%-20s : %10s\n","Running Status", (running_stat ? "Normal" : "Abnormal"));
    CTC_DKIT_PRINT("------------------------------------------\n");

    return CLI_SUCCESS;
    
}

int32
_ctc_tmm_dkit_msic_serdes_fw_unload(uint8 lchip, uint8 serdes_id)
{
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_LOAD_MAGIC_WORD_ADDR, 0x0, 0xfff0);

    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x980d, 0x0, 0xaaa);
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x980d, 0x0, 0x000);

    sal_task_sleep(100); 
    
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_LOAD_MAGIC_WORD_ADDR, 0x0, 0x0);

    /*Clear Break points when running without FW*/
    if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_ADDR_PAM4, 0x0, 0x0);
    }
    else
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_ADDR_NRZ, 0x0, 0x0);
    }
    
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x982E, 0xFFFE, 0);//Clear GPIO bit 0 [0]
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x982D, 0xFFFD, 1);//Clear GPIO bit 0 [1]

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_msic_serdes_fw_load(uint8 lchip, uint8 serdes_id)
{
#if 0
    uint8 *p_data = NULL;
    uint16 FW0 = 0x9F00;//+lane*0x2000 #0x9F00
    uint16 FW1 = 0x980D;//+lane*0x2000 #0x9802
    uint16 FW2 = 0x9814;//+lane*0x2000 #0x9805
    uint32 sections = 0;
    uint32 index = 0;
    uint8 n = 0;
    uint16 status = 0xffff;
    uint16 mdio_data;
    uint32 check_time = 0;
    uint16 check_sum = 0x0000;
    uint32 dataPtr = 0;
    uint32 ram_addr;

    _ctc_tmm_dkit_msic_serdes_fw_unload(lchip, serdes_id);
    CTC_DKIT_PRINT("\n...SerDes %d Downloading  FW : ...\n", serdes_id);

    /*Read Data*/
    p_data = g_dkits_tmm_firmware + CTC_DKIT_SERDES_FIREWARE_FILE_HEADER_RSV_SIZE + sizeof(ctc_dkit_tmm_serdes_fw_header_t);

    _ctc_tmm_dkit_misc_serdes_get_fw_header(lchip);
    ram_addr = g_dkit_tmm_fm_header->ram_addr;

    sections = (uint32)(g_dkit_tmm_fm_header->length + 23) / 24;
    
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW2, 0x0, 0xFFF0);
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW1, 0x0, 0x0AAA);
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW1, 0x0, 0x0000);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW2, 0x0, &status);
    
    while(status != 0)
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW2, 0x0, &status);
        check_time += 1;
        if(check_time > 100000)
        {
            CTC_DKIT_PRINT("\n...FW LOAD ERROR: : Wait for FW2=0 Timed Out! FW2 = 0x%x\n", status);
            break;
        }
    }

    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW2, 0x0, 0x0000);
    
    while(index < sections)
    {
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 12, 0x0, (uint16)(ram_addr >> 16));
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 13, 0x0, (uint16)(ram_addr & 0xFFFF));

        for(n = 0; n < 12; n++)
        {
            if(dataPtr >= g_dkit_tmm_fm_header->length)
            {
                mdio_data = 0x0000;
            }
            else
            {
                mdio_data = (uint16)((p_data[dataPtr] << 8) + p_data[dataPtr + 1]);
            }
            _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + n, 0x0, mdio_data);

            dataPtr += 2;
            ram_addr += 2;
        }

        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 14, 0x0, check_sum);

        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 15, 0x0, 0x800C);

        check_time = 0;
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 15, 0x0, &status);
        
        while((status & (~(1 << 13))) == 0x800C)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 15, 0x0, &status);
            check_time += 1;

            if (check_time > 1000)
            {
                CTC_DKIT_PRINT("\n...FW LOAD ERROR: Write ro RAM Timed Out! FW0 = %x\n", status);
                break;
            }
        }
        if((status & (~(1 << 13))) != 0)       
        {
            CTC_DKIT_PRINT("\n...FW LOAD ERROR: Invalid Write to RAM, section %d status %d\n", index, status);
            return CLI_ERROR;
        }

        index += 1;
    }

    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 12, 0x0, (uint16)(g_dkit_tmm_fm_header->entry_point >> 16));
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 13, 0x0, (uint16)(g_dkit_tmm_fm_header->entry_point & 0xFFFF));

    check_sum = (g_dkit_tmm_fm_header->entry_point >> 16) + (g_dkit_tmm_fm_header->entry_point & 0xFFFF) + 0x4000;

    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 14, 0x0, check_sum);

    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW0 + 15, 0x0, 0x4000);


    sal_task_sleep(1000); //wait more than one second 

    CTC_DKIT_PRINT(" Hash Code : 0x%06x\n", g_dkit_tmm_fm_header->hash_code);
    CTC_DKIT_PRINT(" Date Code : 0x%02x\n", g_dkit_tmm_fm_header->date);
    CTC_DKIT_PRINT(" CRC Code  : 0x%04x\n", g_dkit_tmm_fm_header->crc16);
    CTC_DKIT_PRINT(" Length   : %d\n", g_dkit_tmm_fm_header->length);
    CTC_DKIT_PRINT(" Entry    : 0x%08x\n", g_dkit_tmm_fm_header->entry_point);
    CTC_DKIT_PRINT(" RAM      : 0x%08x\n",g_dkit_tmm_fm_header->ram_addr);
#endif

    McPcsX8LanesRsv_m lt_mode;
    uint32 cmd;
    uint32 value = 0;

    cmd = DRV_IOR(McPcsX8LanesRsv_t, DRV_ENTRY_FLAG);
    (void)DRV_IOCTL(lchip, 0, cmd, &lt_mode);
    DRV_IOR_FIELD(lchip, McPcsX8LanesRsv_t, McPcsX8LanesRsv_rsv_0_rsv_f, &value, &lt_mode);
    value = 1 - value; /*get opposite*/
    DRV_IOW_FIELD(lchip, McPcsX8LanesRsv_t, McPcsX8LanesRsv_rsv_0_rsv_f, &value, &lt_mode);
    cmd = DRV_IOW(McPcsX8LanesRsv_t, DRV_ENTRY_FLAG);
    (void)DRV_IOCTL(lchip, 0, cmd, &lt_mode);
    CTC_DKIT_PRINT(" FW train option      : 0x%08x\n", value);

    return CLI_SUCCESS;
}

STATIC int32
_ctc_tmm_dkit_misc_serdes_fw(uint8 lchip, void *p_data)
{
    uint16 serdes_id = 0;
    ctc_dkit_tmm_serdes_ctl_fw_t *p_fw;

    p_fw = (ctc_dkit_tmm_serdes_ctl_fw_t *)p_data;

    serdes_id = p_fw->serdes_id;

    switch(p_fw->oper)
    {
        case 0:
            /*GET FW_RUNNING STAUS*/
            _ctc_tmm_dkit_msic_serdes_get_fw_status(lchip, serdes_id);
            break;
        case 1:
            /*Load Firmware*/
            _ctc_tmm_dkit_msic_serdes_fw_load(lchip, serdes_id);
            break;
        case 2:
            /*Unload Firmware*/
            _ctc_tmm_dkit_msic_serdes_fw_unload(lchip, serdes_id);
            break;
        default :
            CTC_DKIT_PRINT("Feature not supported!\n");
            break;
    }

    return CLI_SUCCESS;
}


/*serdes SERDES_ID reset*/
int32
ctc_tmm_dkit_misc_serdes_resert(uint8 lchip, uint16 serdes_id)
{
    uint16 curr_tgt_init;
    uint16 curr_tgt_final;

    CTC_DKIT_LCHIP_CHECK(lchip);

    if(CTC_DKIT_TMM_SERDES_PAM4_MODE != _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        /*NRZ Mode lane Reset is a simple lane-reset toggle*/
        _ctc_tmm_dkit_misc_serdes_lane_reset_toggle(lchip, serdes_id, 10);
        _ctc_tmm_dkit_misc_serdes_wait_tuning_done(lchip, serdes_id);
    }
    else
    {
        /*Clear Break points when running without FW*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, SM_CTRL_ADDR_PAM4, 0x0, 0x0);
        /*typcially 3*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, OW_MU_OFFSET_ADDR, OW_MU_OFFSET_MASK, 0);

        /*Save the original settigns for cntr targets before lane reset*/
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, CNTR_TARGET_INIT_ADDR_PAM4, CNTR_TARGET_INIT_MASK_PAM4, &curr_tgt_init);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, CNTR_TARGET_FINAL_ADDR_PAM4, CNTR_TARGET_FINAL_MASK_PAM4, &curr_tgt_final);

        /*rewrite cntr targets to the above values for lane reset*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, CNTR_TARGET_INIT_ADDR_PAM4, CNTR_TARGET_INIT_MASK_PAM4, 0x8000);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, CNTR_TARGET_FINAL_ADDR_PAM4, CNTR_TARGET_FINAL_MASK_PAM4, 0x4000);

        _ctc_tmm_dkit_misc_serdes_lane_reset_toggle(lchip, serdes_id, 10);
        sal_task_sleep(400);

        /*Restore the original settings for cntr targets before lane reset*/
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, CNTR_TARGET_INIT_ADDR_PAM4, CNTR_TARGET_INIT_MASK_PAM4, curr_tgt_init);
        _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, CNTR_TARGET_FINAL_ADDR_PAM4, CNTR_TARGET_FINAL_MASK_PAM4, curr_tgt_final);
    }

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_pam4_status(uint8 lchip, uint16 serdes_id, uint32 type, char* file_name)
{
    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_get_ctle(uint8 lchip, uint8 serdes_id, uint8 *index, uint16 *c1, uint16 *c2)
{
	uint16 map[8][2];
	uint16 data;
    uint16 ctle_map0_addr = CTLE_MAP0_ADDR_PAM4;
    uint16 ctle_map1_addr = CTLE_MAP1_ADDR_PAM4;
    uint16 ctle_map2_addr = CTLE_MAP2_ADDR_PAM4;
    uint16 ctle_val_addr = CTLE_VAL_ADDR_PAM4;
    uint16 ctle_val_mask = CTLE_VAL_MASK_PAM4;
    uint16 ctle_en_addr = CTLE_EN_ADDR_PAM4;
    uint16 ctle_en_mask = CTLE_EN_MASK_PAM4;

    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        ctle_map0_addr = CTLE_MAP0_ADDR_NRZ;
        ctle_map1_addr = CTLE_MAP1_ADDR_NRZ;
        ctle_map2_addr = CTLE_MAP2_ADDR_NRZ;
        ctle_val_addr = CTLE_VAL_ADDR_NRZ;
        ctle_val_mask = CTLE_VAL_MASK_NRZ;
        ctle_en_addr = CTLE_EN_ADDR_NRZ;
        ctle_en_mask = CTLE_EN_MASK_NRZ;
    }

    /*make sure CTLE OW is enabled*/
    _ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_en_addr, ctle_en_mask, 1);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map2_addr, 0x1fff, &map[0][0]);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map2_addr, 0xe3ff, &map[0][1]);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map2_addr, 0xfc7f, &map[1][0]);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map2_addr, 0xff8f, &map[1][1]);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map2_addr, 0xfff1, &map[2][0]);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map2_addr, 0xfffe, &data);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map1_addr , 0x3fff, &map[2][1]);
    map[2][1] += (data << 2);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map1_addr , 0xc7ff, &map[3][0]);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map1_addr , 0xf8ff, &map[3][1]);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map1_addr , 0xff1f, &map[4][0]);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map1_addr , 0xffe3, &map[4][1]);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map1_addr , 0xfffc, &data);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map0_addr, 0x7fff, &map[5][0]);
    map[5][0] += (data << 1);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map0_addr, 0x8fff, &map[5][1]);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map0_addr, 0xf1ff, &map[6][0]);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map0_addr, 0xfe3f, &map[6][1]);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map0_addr, 0xffc7, &map[7][0]);
    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_map0_addr, 0xfff8, &map[7][1]);

    _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, ctle_val_addr, ctle_val_mask, &data);

    *index = (uint8)data;
    *c1 = map[*index][0];
    *c2 = map[*index][1];

    return CLI_SUCCESS;
}

uint16 ctc_tmm_dkit_misc_serdes_gray_to_bin(uint16 gray)
{
     uint16 bin = 0;

     for(bin = 0; bin < 0xffff; bin ++)
     {
        if(gray == CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(bin))
        {
            break;
        }
     }

     return bin;
}

void
ctc_tmm_dkit_misc_serdes_comp_ofst(uint8 lchip, uint16 serdes_id, sal_file_t p_file)
{
    uint8 base_idx;
    uint8 dir;
    uint8 phase;
    uint8 addr;
    uint16 base_addr[]     = {0x0000, 0x2000, 0x4000};
    uint16 adr_comp_addr   = 0xe0;
    uint16 reg_addr_comp   = 0;
    uint16 reg_mask_comp[] = {0xefff, 0xff3f, 0xf0ff};
    uint16 clp_caln_addr   = 0xd7;
    uint16 reg_addr_calp   = 0;
    uint16 reg_mask_calp[] = {0x03ff, 0xfc0f};
    uint16 calp = 0;
    uint16 caln = 0;

    for(base_idx = 0; base_idx < 3; base_idx++)
    {
        reg_addr_comp = base_addr[base_idx] + adr_comp_addr;
        reg_addr_calp = base_addr[base_idx] + clp_caln_addr;
        for(dir = 0; dir < 2; dir++)
        {
            for(phase = 0; phase < 4; phase++)
            {
                for(addr = 0; addr < 16; addr++)
                {
                    (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 
                        reg_addr_comp, reg_mask_comp[0], dir);
                    (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 
                        reg_addr_comp, reg_mask_comp[1], phase);
                    (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 
                        reg_addr_comp, reg_mask_comp[2], addr);
                    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 
                        reg_addr_calp, reg_mask_calp[0], &calp);
                    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 
                        reg_addr_calp, reg_mask_calp[1], &caln);
                    CTC_DKITS_PRINT_FILE(p_file, 
                        " base->0x%04x; dir->%d; phase->%2d; addr->%3d; calp->%3d; caln->%3d; |diff|->%3d\n", 
                        base_addr[base_idx], dir, phase, addr, calp, caln, calp>caln?(calp-caln):(caln-calp));
                }
            }
        }
    }

}

void
ctc_tmm_dkit_misc_serdes_dump_enhance_printval(uint8 lchip, uint8 print_type, uint16 value, sal_file_t p_file)
{
    uint32 tmp_u32 = 0;
    uint16 tmp_u16_1 = 0;
    uint16 tmp_u16_2 = 0;
    switch(print_type)
    {
        case 1: /*UINT16_T*/
            CTC_DKITS_PRINT_FILE(p_file, "%d ", value);
            break;
        case 2: /*INT16_T*/
            tmp_u32 = value;
            if(DKITS_FLAG_ISSET(value, 0x8000))
            {
                tmp_u32 -= 0x10000;
            }
            CTC_DKITS_PRINT_FILE(p_file, "%d ", tmp_u32);
            break;
        case 3: /*INT8_T*/
            tmp_u32 = value & 0x00ff;
            if(DKITS_FLAG_ISSET(tmp_u32, 0x80))
            {
                tmp_u32 -= 0x10;
            }
            CTC_DKITS_PRINT_FILE(p_file, "%d ", tmp_u32);
            break;
        case 4: /*UINT8_T*/
            CTC_DKITS_PRINT_FILE(p_file, "%d ", value & 0x00ff);
            break;
        case 5: /*UINT16_T_8_8*/
            tmp_u16_1 = (value >> 8) & 0x00ff;
            tmp_u16_2 = value & 0x00ff;
            CTC_DKITS_PRINT_FILE(p_file, "(%d, %d) ", tmp_u16_1, tmp_u16_2);
            break;
        case 6: /*UINT16_T_HEX*/
            CTC_DKITS_PRINT_FILE(p_file, "0x%04x ", value);
            break;
        default:
            CTC_DKITS_PRINT_FILE(p_file, "data type unknown! ");
            break;
    }
}

void
ctc_tmm_dkit_misc_serdes_dump_enhance(uint8 lchip, uint8 serdes_id, char* name, uint16 index_list[], uint8 index_num, 
                                                  uint8 print_type, uint8 mode, sal_file_t p_file)
{
    uint8 item_flag = 0;
    uint8 i = 0;
    uint8 j = 0;
    uint16 value = 0;

    if(3 < index_num)
    {
        return;
    }

    for(i = 0; i < index_num; i++)
    {
        if(65535 != index_list[i])
        {
            item_flag++;
        }
    }

    switch(item_flag)
    {
        case 1:
            CTC_DKITS_PRINT_FILE(p_file, "%s: ", name);
            (void)_ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, mode, index_list[0], &value);
            ctc_tmm_dkit_misc_serdes_dump_enhance_printval(lchip, print_type, value, p_file);
            CTC_DKITS_PRINT_FILE(p_file, "\n");
            break;
        case 2:
            CTC_DKITS_PRINT_FILE(p_file, "%s: ", name);
            for(j = 0; j < index_list[1]; j++)
            {
                (void)_ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, mode, (uint16)(index_list[0]+j), &value);
                ctc_tmm_dkit_misc_serdes_dump_enhance_printval(lchip, print_type, value, p_file);
            }
            CTC_DKITS_PRINT_FILE(p_file, "\n");
            break;
        case 3:
            CTC_DKITS_PRINT_FILE(p_file, "%s:\n", name);
            for(j = 0; j < index_list[1]; j++)
            {
                CTC_DKITS_PRINT_FILE(p_file, "         ");
                for(i = 0; i < index_list[2]; i++)
                {
                    (void)_ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, mode, (uint16)(index_list[0]+i*j), &value);
                    ctc_tmm_dkit_misc_serdes_dump_enhance_printval(lchip, print_type, value, p_file);
                }
                CTC_DKITS_PRINT_FILE(p_file, "\n");
            }
            break;
        default:
            break;
    }
}

void
ctc_tmm_dkit_misc_serdes_dump_enhance_nrz(uint8 lchip, uint8 serdes_id, sal_file_t p_file)
{
    uint8  item = 0;
    char*  item_name[11] = {
        "DC_SEARCH_CNT      ",
        "DC_SEARCH_GAIN1    ",
        "DC_SEARCH_GAIN2    ",
        "EM                 ",
        "EM_STATE           ",
        "RECOVER_COUNT      ",
        "ATTN_OF1           ",
        "ATTN_OF2           ",
        "RX_S24_RETRY       ",
        "RX_S24_DEGEN_RETRY ",
        "MARGIN_MAX_TARGET  ",
    };
    uint16 index_list[11][3] = {
        {140, 16   , 65535}, 
        {160, 16   , 65535}, 
        {180, 16   , 65535}, 
        {300, 4    , 65535}, 
        {10 , 65535, 65535}, 
        {60 , 65535, 65535}, 
        {26 , 65535, 65535}, 
        {27 , 65535, 65535}, 
        {6  , 65535, 65535}, 
        {9  , 65535, 65535}, 
        {8  , 65535, 65535}, 
    };
    uint8 print_type[11] = {
        1, 
        4, 
        4, 
        2, 
        6, 
        1, 
        4, 
        4, 
        1, 
        1, 
        2, 
    };

    for(item = 0; item < 11; item++)
    {
        ctc_tmm_dkit_misc_serdes_dump_enhance(lchip, serdes_id, item_name[item], index_list[item], 3, print_type[item], 1, p_file);
    }
}

void
ctc_tmm_dkit_misc_serdes_dump_enhance_pam4(uint8 lchip, uint8 serdes_id, sal_file_t p_file)
{
    uint8  item = 0;
    char*  item_name[27] = {
        "GAIN_CHANGE        ",
        "GAIN_METRIC        ",
        "GAIN_UPDATE        ",
        "CTLE_SEARCH        ",
        "ISI_CTLE_SEARCH    ",
        "SKEF_ISI2          ",
        "RX_RATIO           ",
        "RX_FINAL_OF        ",
        "RX_FINAL_HF        ",
        "PAM4_OPTION        ",
        "S0_AGCGAIN         ",
        "START_TIME         ",
        "ANALYZER0_TIME     ",
        "ANALYZER_ATTN_TIME ",
        "S2_F0              ",
        "S2_F1              ",
        "S2_DAC_READ        ",
        "EYE_CHK            ",
        "PPM_CHK            ",
        "SKEF_START         ",
        "ATTN_OF1           ",
        "ATTN_OF2           ",
        "RECOVER_COUNT      ",
        "START_TIME         ",
        "ANALYZER0_TIME     ",
        "ANALYZER_ATTN_TIME ",
        "RX_STATE           ",
    };
    uint16 index_list[27][3] = {
        {120, 3    , 65535},
        {125, 12   , 65535},
        {140, 12   , 65535},
        {53 , 4    , 65535},
        {170, 2    , 4    },
        {320, 9    , 65535},
        {3  , 65535, 65535},
        {1  , 65535, 65535},
        {2  , 65535, 65535},
        {11 , 65535, 65535},
        {33 , 65535, 65535},
        {20 , 65535, 65535},
        {21 , 65535, 65535},
        {22 , 65535, 65535},
        {42 , 65535, 65535},
        {43 , 65535, 65535},
        {44 , 65535, 65535},
        {46 , 65535, 65535},
        {48 , 65535, 65535},
        {57 , 65535, 65535},
        {51 , 65535, 65535},
        {52 , 65535, 65535},
        {60 , 65535, 65535},
        {20 , 65535, 65535},
        {21 , 65535, 65535},
        {22 , 65535, 65535},
        {0  , 65535, 65535},
    };
    uint8 print_type[27] = {
        1, 
        1, 
        1, 
        3, 
        2, 
        1, 
        1, 
        4, 
        4, 
        1, 
        5, 
        1, 
        1, 
        1, 
        2, 
        2, 
        4, 
        2, 
        2, 
        3, 
        4, 
        4, 
        1, 
        1, 
        1, 
        1, 
        6, 
    };

    for(item = 0; item < 27; item++)
    {
        ctc_tmm_dkit_misc_serdes_dump_enhance(lchip, serdes_id, item_name[item], index_list[item], 3, print_type[item], 2, p_file);
    }
}

/*serdes SERDES_ID dump*/
int32
ctc_tmm_dkit_misc_serdes_status(uint8 lchip, uint16 serdes_id, uint32 type, char* file_name)
{
    sal_time_t tv;
    char* p_time_str = NULL;
    sal_file_t p_file = NULL;
    uint32 index = 0, n = 0;
    uint32 eye_margin = 0;
    uint32 eye_min = 0xffff;
    uint32 eye_max = 0;
    uint32 eye3_margin[3] = {0,0,0};
    uint32 eye3_min[3] = {0xffff, 0xffff, 0xffff};
    uint32 eye3_max[3] = {0,0,0};
    uint32 eye3_sum[3] = {0,0,0};
    uint32 sum = 0;
    uint8 ctle_index = 0;
    uint16 ctle_c0 = 0, ctle_c1 = 0;
    uint16 addr = 0;
    uint16 data = 0;
    uint16 tmp_data = 0;
    int32 tap_1_pam4_abs = 0;
    int32 tap_2_pam4_abs = 0;
    uint8 fw_is_running = 0;
    uint32 data_rate = 0;
    int16 delta = 0;
    int16 fm1 = 0;
    uint16 pt_dbg = 0;
    ctc_dkit_tmm_serdes_ctl_dfe_t dfe_param;
    ctc_tmm_dkit_misc_serdes_tx_taps_param_t tx_taps;

    DKITS_SERDES_ID_CHECK(serdes_id);
    CTC_DKIT_LCHIP_CHECK(lchip);

    if (file_name)
    {
        p_file = sal_fopen(file_name, "wt");
        if (!p_file)
        {
            CTC_DKIT_PRINT("Open file %s fail!!!\n", file_name);
            return CLI_SUCCESS;
        }
    }
    /*get systime*/
    sal_time(&tv);
    p_time_str = sal_ctime(&tv);
    CTC_DKITS_PRINT_FILE(p_file, "# Serdes %d Regs Status, %s", serdes_id, p_time_str);

    if ((CTC_DKIT_SERDES_ALL == type) || (CTC_DKIT_SERDES_DETAIL == type))
    {
        /*DUMP REG*/
        CTC_DKITS_PRINT_FILE(p_file, "# Registers : 00xx\n");
        for (addr = 0x0000; addr <= 0x00FF; addr++)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, &data);
            CTC_DKITS_PRINT_FILE(p_file, "Read  0x%02x: 0x%04x\n", addr, data);
        }

        CTC_DKITS_PRINT_FILE(p_file, "# Registers, 01xx\n");
        for (addr = 0x0100; addr <= 0x01FF; addr++)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, &data);
            CTC_DKITS_PRINT_FILE(p_file, "Read  0x%02x: 0x%04x\n", addr, data);
        }

        CTC_DKITS_PRINT_FILE(p_file, "# Registers, 80xx\n");
        for (addr = 0x8000; addr <= 0x80FF; addr++)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, &data);
            CTC_DKITS_PRINT_FILE(p_file, "Read  0x%02x: 0x%04x\n", addr, data);
        }

        CTC_DKITS_PRINT_FILE(p_file, "# Registers, 81xx\n");
        for (addr = 0x8100; addr <= 0x81FF; addr++)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, &data);
            CTC_DKITS_PRINT_FILE(p_file, "Read  0x%02x: 0x%04x\n", addr, data);
        }

        CTC_DKITS_PRINT_FILE(p_file, "# Registers, 82xx, 83xx, 84xx\n");
        for (addr = 0x8200; addr <= 0x84FF; addr++)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, &data);
            CTC_DKITS_PRINT_FILE(p_file, "Read  0x%02x: 0x%04x\n", addr, data);
        }

        CTC_DKITS_PRINT_FILE(p_file, "# Registers, 97xx\n");
        for (addr = 0x9700; addr <= 0x97FF; addr++)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, &data);
            CTC_DKITS_PRINT_FILE(p_file, "Read  0x%02x: 0x%04x\n", addr, data);
        }

        CTC_DKITS_PRINT_FILE(p_file, "# Registers, 98xx\n");
        for (addr = 0x9800; addr <= 0x98FF; addr++)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, &data);
            CTC_DKITS_PRINT_FILE(p_file, "Read  0x%02x: 0x%04x\n", addr, data);
        }

        CTC_DKITS_PRINT_FILE(p_file, "# Registers, 9Fxx\n");
        for (addr = 0x9F00; addr <= 0x9FFF; addr++)
        {
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, addr, 0x0, &data);
            CTC_DKITS_PRINT_FILE(p_file, "Read  0x%02x: 0x%04x\n", addr, data);
        }
    }

    if ((CTC_DKIT_SERDES_ALL == type) || (CTC_DKIT_SERDES_DETAIL == type) || 
        (CTC_DKIT_SERDES_RX == type) || (CTC_DKIT_SERDES_TX == type))
    {
        /*Eye Scan*/
        fw_is_running = _ctc_tmm_dkit_misc_serdes_is_fw_running(lchip, serdes_id);
        CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
        CTC_DKITS_PRINT_FILE(p_file, "\n Eye height measure\n");
        if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {       
            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
            CTC_DKITS_PRINT_FILE(p_file, " %-10s%-10s\n", "No.", "EyeOpen");
            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
            for(index = 0; index < 3; index ++)
            {
                eye_margin = _ctc_tmm_dkit_misc_serdes_get_eye(lchip, serdes_id, fw_is_running, NULL);
                sum += eye_margin;

                eye_max = (eye_margin > eye_max ? eye_margin : eye_max);
                eye_min = (eye_margin < eye_min ? eye_margin : eye_min);

                CTC_DKITS_PRINT_FILE(p_file, " %-10d%-4d\n", index + 1, eye_margin);
            }

            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
            CTC_DKITS_PRINT_FILE(p_file, " %-10s%-10d\n","Min", eye_min );
            CTC_DKITS_PRINT_FILE(p_file, " %-10s%-10d\n","Max", eye_max);
            CTC_DKITS_PRINT_FILE(p_file, " %-10s%-10d\n","Avg", (sum / 3));
        }
        else
        {
            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
            CTC_DKITS_PRINT_FILE(p_file, " %-10s%-10s%-10s%-10s\n", "No.", "Eye1_Open","Eye2_Open","Eye3_Open");
            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
            for(index = 0; index < 3; index ++)
            {
                _ctc_tmm_dkit_misc_serdes_get_eye3(lchip, serdes_id, fw_is_running, eye3_margin, NULL);

                for(n = 0; n < 3; n ++)
                {
                    eye3_sum[n] += eye3_margin[n];
                    eye3_max[n] = (eye3_margin[n] > eye3_max[n] ? eye3_margin[n] : eye3_max[n]);
                    eye3_min[n] = (eye3_margin[n] < eye3_min[n] ? eye3_margin[n] : eye3_min[n]);
                }

                CTC_DKITS_PRINT_FILE(p_file, " %-10d  %-10d  %-10d  %-10d\n", index + 1, eye3_margin[0], eye3_margin[1], eye3_margin[2]);
            }

            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
            CTC_DKITS_PRINT_FILE(p_file, " %-10s  %-10d  %-10d  %-10d\n","Min", eye3_min[0], eye3_min[1], eye3_min[2]);
            CTC_DKITS_PRINT_FILE(p_file, " %-10s  %-10d  %-10d  %-10d\n", "Max", eye3_max[0], eye3_max[1], eye3_max[2]);
            CTC_DKITS_PRINT_FILE(p_file, " %-10s  %-10d  %-10d  %-10d\n", "Avg", eye3_sum[0] / 3, eye3_sum[1] / 3, eye3_sum[2] / 3);
        }

        /*DFE*/
        dfe_param.serdes_id = serdes_id;
        dfe_param.oper = CTC_DKIT_SERDIS_CTL_GET_DFE;
        
        _ctc_tmm_dkit_misc_serdes_dfe_get_val(lchip, &dfe_param);

        if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
            CTC_DKITS_PRINT_FILE(p_file, " DFE status\n");
            CTC_DKITS_PRINT_FILE(p_file, " Tap1 val: %d\n", dfe_param.taps[0]);
            CTC_DKITS_PRINT_FILE(p_file, " Tap2 val: %d\n", dfe_param.taps[1]);
            CTC_DKITS_PRINT_FILE(p_file, " Tap3 val: %d\n", dfe_param.taps[2]);
            CTC_DKITS_PRINT_FILE(p_file, " Delta val: %d\n", dfe_param.taps[3]);
            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
        }
        else
        {
            tap_1_pam4_abs = ((dfe_param.taps_pam4[0] > 0) ? dfe_param.taps_pam4[0] : (0 - dfe_param.taps_pam4[0]));
            tap_2_pam4_abs = ((dfe_param.taps_pam4[1] > 0) ? dfe_param.taps_pam4[1] : (0 - dfe_param.taps_pam4[1]));
            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
            CTC_DKITS_PRINT_FILE(p_file, " DFE status\n");
            CTC_DKITS_PRINT_FILE(p_file, " Tap1 val: %s%d.%08d\n", (dfe_param.taps_pam4[0] >= 0 ? "" : "-"), (tap_1_pam4_abs / 100000000), (tap_1_pam4_abs % 100000000));
            CTC_DKITS_PRINT_FILE(p_file, " Tap2 val: %s%d.%08d\n", (dfe_param.taps_pam4[1] >= 0 ? "" : "-"), (tap_2_pam4_abs / 100000000), (tap_2_pam4_abs % 100000000));
            CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
        }

        /*FFE*/
        tx_taps.serdes_id = serdes_id;
        _ctc_tmm_dkit_misc_serdes_get_tx_taps(lchip, &tx_taps);
        CTC_DKITS_PRINT_FILE(p_file, " FFE config\n");
        CTC_DKITS_PRINT_FILE(p_file, "  c0: %d\n", tx_taps.taps_param[0]);
        CTC_DKITS_PRINT_FILE(p_file, "  c1: %d\n", tx_taps.taps_param[1]);
        CTC_DKITS_PRINT_FILE(p_file, "  c2: %d\n", tx_taps.taps_param[2]);
        CTC_DKITS_PRINT_FILE(p_file, "  c3: %d\n", tx_taps.taps_param[3]);
        CTC_DKITS_PRINT_FILE(p_file, "  c4: %d\n", tx_taps.taps_param[4]);
        CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");

        /*CTLE*/
        _ctc_tmm_dkit_misc_serdes_get_ctle(lchip, serdes_id, &ctle_index, &ctle_c0, &ctle_c1);
        CTC_DKITS_PRINT_FILE(p_file, " CTLE config:\n");
        CTC_DKITS_PRINT_FILE(p_file, " ctle_index : %d\n", ctle_index);
        CTC_DKITS_PRINT_FILE(p_file, " ctle_c0 : %d\n", ctle_c0);
        CTC_DKITS_PRINT_FILE(p_file, " ctle_c1 : %d\n", ctle_c1);
        CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");

        ctc_tmm_dkit_misc_serdes_dump_exit_code(lchip, serdes_id, p_file);
        CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
        if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            ctc_tmm_dkit_misc_serdes_dump_enhance_pam4(lchip, serdes_id, p_file);
        }
        else
        {
            ctc_tmm_dkit_misc_serdes_dump_enhance_nrz(lchip, serdes_id, p_file);
        }
        CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");

        CTC_DKITS_PRINT_FILE(p_file, " SerDes %d Params:\n", serdes_id);
        _ctc_tmm_dkit_misc_serdes_get_datarate(lchip, serdes_id, &data_rate);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d.%05d\n", " Actual DataRate", (data_rate / 100000), (data_rate % 100000));

        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %s\n", " FW Running Status", (fw_is_running == 1) ? "Running" : "Halting");

        _ctc_tmm_dkit_misc_serdes_get_fw_reg(lchip, serdes_id, 5, 0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " FW Tuning Counter",data);

        _ctc_tmm_dkit_misc_serdes_get_fw_reg(lchip, serdes_id, 4, 0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " FW Reset Counter",data);

        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FW_TUNING_STATUS_ADDR, 0x0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: 0x%0x [%s]\n", " FW Tuning Status", data, (data == 0x4 ? "Done" : (data == 0x8 ? "Failed" : "Time Out")));
        /*ctle_gain1_bit_loc = [14,8]*/
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, CTLE_GAIN1_ADDR, 0x80ff, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " CTLE Gain1", ctc_tmm_dkit_misc_serdes_gray_to_bin(data));
        /*ctle_gain2_bit_loc = [6,0]*/
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, CTLE_GAIN2_ADDR, 0xff80, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " CTLE Gain2", ctc_tmm_dkit_misc_serdes_gray_to_bin(data));
        
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_GAIN1_ADDR, 0xf0ff, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " FFE Gain1", ctc_tmm_dkit_misc_serdes_gray_to_bin(data));
        
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_GAIN2_ADDR, 0xfff0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " FFE Gain2", ctc_tmm_dkit_misc_serdes_gray_to_bin(data));

         _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x01f4, 0xf3ff, &data);
         CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d [%s]\n", " AGC ATTN",data, (data == 0 ? "No attenuation" : (data == 1 ? "1.5dB attenuation" : "3.0dB attenuation")));

        _ctc_tmm_dkit_misc_serdes_get_fw_reg(lchip, serdes_id, 11, 0, &data);
        data = data * 1000 / 256;
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d.%03d\n", " Channel Estimate", (data / 1000), (data % 1000));

        _ctc_tmm_dkit_misc_serdes_get_fw_reg(lchip, serdes_id, 9, 0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " Channel OF",data);

        _ctc_tmm_dkit_misc_serdes_get_fw_reg(lchip, serdes_id, 10, 0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " Channel HF",data);

        if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
        {
            CTC_DKITS_PRINT_FILE(p_file, " %-20s: %s%d.%08d\n", " f0", (dfe_param.taps_pam4[0] >= 0 ? "" : "-"), (tap_1_pam4_abs / 100000000), (tap_1_pam4_abs % 100000000));
            CTC_DKITS_PRINT_FILE(p_file, " %-20s: %s%d.%08d\n", " f1", (dfe_param.taps_pam4[1] >= 0 ? "" : "-"), (tap_2_pam4_abs / 100000000), (tap_2_pam4_abs % 100000000));
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, PAM4_TAP_ADDR, 0xff80, &data);
            fm1 = ((data + 64) % 128 - 64) * 100 / 64;
            CTC_DKITS_PRINT_FILE(p_file, " %-20s: %s%d.%02d\n", " fm1", (fm1 >= 0 ? "" : "-"), (fm1 / 100), (fm1 % 100));
            _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DELTA_PH_OW_ADDR_PAM4, \
                                                                                   DELTA_PH_OW_VAL_MASK_PAM4, &data);
            sal_memcpy(&delta, &data , sizeof(uint16));
            delta = (delta > 0x40) ? (delta - 0x80) : delta;
            CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " delta-ph", ((data + 64) % 128 - 64));
        }

        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, F1OVER3_ADDR, 0xf01f, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " f1over3", ((data > 0x40) ? ((int16)data - 0x80) : data));

        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, EDGE1_ADDR, 0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " EDGE", data);
        
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_POL_ADDR, 0, &data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_pol1", ((data >> 9) & 0x1));
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_pol2", ((data >> 8) & 0x1));
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_pol3", ((data >> 7) & 0x1));
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_pol4", ((data >> 6) & 0x1));

        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP1_ADDR, 0x0fff, &data);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP1_ADDR, 0xf0ff, &tmp_data);
        data = ctc_tmm_dkit_misc_serdes_gray_to_bin(data);
        tmp_data = ctc_tmm_dkit_misc_serdes_gray_to_bin(tmp_data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_tap1_bin", (((data << 4) + tmp_data) & 0xff));

        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP2_ADDR, 0xff0f, &data);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP2_ADDR, 0xfff0, &tmp_data);
        data = ctc_tmm_dkit_misc_serdes_gray_to_bin(data);
        tmp_data = ctc_tmm_dkit_misc_serdes_gray_to_bin(tmp_data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_tap2_bin", (((data << 4) + tmp_data) & 0xff));


        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP3_ADDR, 0x0fff, &data);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP3_ADDR, 0xf0ff, &tmp_data);
        data = ctc_tmm_dkit_misc_serdes_gray_to_bin(data);
        tmp_data = ctc_tmm_dkit_misc_serdes_gray_to_bin(tmp_data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_tap3_bin", (((data << 4) + tmp_data) & 0xff));

        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP4_ADDR, 0xff0f, &data);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP4_ADDR, 0xfff0, &tmp_data);
        data = ctc_tmm_dkit_misc_serdes_gray_to_bin(data);
        tmp_data = ctc_tmm_dkit_misc_serdes_gray_to_bin(tmp_data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_tap4_bin", (((data << 4) + tmp_data) & 0xff));

        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP34_ADDR, 0xff0f, &data);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP34_ADDR, 0xfff0, &tmp_data);
        data = ctc_tmm_dkit_misc_serdes_gray_to_bin(data);
        tmp_data = ctc_tmm_dkit_misc_serdes_gray_to_bin(tmp_data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_tap34_bin", (((data << 4) + tmp_data) & 0xff));

        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP234_ADDR, 0xff0f, &data);
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, FFE_TAP234_ADDR, 0xfff0, &tmp_data);
        data = ctc_tmm_dkit_misc_serdes_gray_to_bin(data);
        tmp_data = ctc_tmm_dkit_misc_serdes_gray_to_bin(tmp_data);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %d\n", " ffe_tap234_bin", (((data << 4) + tmp_data) & 0xff));

        _ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, 4, 60, &pt_dbg);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %u\n", " PT_dbg(mode=4 idx=60)", pt_dbg);
        _ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, 4, 61, &pt_dbg);
        CTC_DKITS_PRINT_FILE(p_file, " %-20s: %u\n", " PT_dbg(mode=4 idx=61)", pt_dbg);

        CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");

        (void)_ctc_tmm_dkit_misc_serdes_status(lchip, serdes_id, p_file);
        CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
    }

    if(CTC_DKIT_SERDES_DETAIL == type)
    {
        (void)ctc_tmm_dkit_misc_serdes_dump_bathtub(lchip, serdes_id, p_file);
        CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
        (void)_ctc_tmm_dkit_misc_serdes_dump_ISI(lchip, serdes_id, p_file);
    }

    if(CTC_DKIT_SERDES_COMMON_PLL == type)
    {
        CTC_DKITS_PRINT_FILE(p_file, " -----------------------------------------------------------------------------\n");
        CTC_DKITS_PRINT_FILE(p_file, " CompOffset_log (serdes %u):\n", serdes_id);
        ctc_tmm_dkit_misc_serdes_comp_ofst(lchip, serdes_id, p_file);
        CTC_DKITS_PRINT_FILE(p_file, " -----------------------------------------------------------------------------\n");
    }

    if (p_file)
    {
        sal_fclose(p_file);
        CTC_DKIT_PRINT("Save result to %s\n", file_name);
    }
    return CLI_SUCCESS;

}

uint32
_ctc_tmm_dkit_misc_serdes_dump_ISI(uint8 lchip, uint8 serdes_id, sal_file_t p_file)
{
    uint16 isi_uint16[16] = {0};
    int16 isi_list[16] = {0};
    uint16 mode = 0;
    uint16 data = 0;
    uint8 index = 0;
    
    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        mode = 0x9;
    }
    else
    {
        mode = 0xa;
    }
    
    _ctc_tmm_dkit_misc_serdes_PT_debug(lchip, serdes_id, mode, 0, &data);
    
    for(index = 0; index < 16; index ++)
    {
        _ctc_tmm_dkit_misc_serdes_fw_read_s16(lchip, serdes_id, index, (isi_uint16 + index));
    }
    
    sal_memcpy(isi_list, isi_uint16, sizeof(uint16) * 16);
    
    CTC_DKITS_PRINT_FILE(p_file, "\n Serdes %d ISI :\n", serdes_id);
    if(CTC_DKIT_TMM_SERDES_PAM4_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        CTC_DKITS_PRINT_FILE(p_file, " %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s |\n", \
                                                "F-2", "F-1", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14");

    }
    else
    {
        CTC_DKITS_PRINT_FILE(p_file, " %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s | %-4s |\n", \
                                                "F-1", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18");

    }

    CTC_DKITS_PRINT_FILE(p_file, " %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d | %-4d |\n", \
                                          isi_list[0], isi_list[1], isi_list[2], isi_list[3], isi_list[4], isi_list[5], isi_list[6], isi_list[7], \
                                             isi_list[8], isi_list[9], isi_list[10], isi_list[11], isi_list[12], isi_list[13], isi_list[14], isi_list[15]);
    CTC_DKITS_PRINT_FILE(p_file, " ---------------------------------------------------------------\n");
    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_get_delta_ph(uint8 lchip, uint8 serdes_id)
{
    uint16 delta = 0;
    int16 delta_int16 = 0;

    if(CTC_DKIT_TMM_SERDES_NRZ_MODE == _ctc_tmm_dkit_misc_get_serdes_mode(lchip, serdes_id))
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DFE_DELTA_ADDR_NRZ, DFE_DELTA_MASK_NRZ, &delta);
    }
    else
    {
        _ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, DELTA_PH_OW_ADDR_PAM4, \
                                                                                    DELTA_PH_OW_VAL_MASK_PAM4, &delta);
    }

    sal_memcpy(&delta_int16, &delta , sizeof(uint16));

    delta_int16 = (delta_int16 > 0x40) ? (delta_int16 - 0x80) : delta_int16; 
    
    CTC_DKIT_PRINT("\n Serdes %d delth-ph:\n", serdes_id);
    CTC_DKIT_PRINT(" Delta-Ph : %d \n", delta_int16);
    CTC_DKIT_PRINT(" ---------------------------------------------------------------\n");
    
    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_ffe_taps(uint8 lchip, uint8 serdes_id, uint16 ffe_tap1, uint16 ffe_tap234, 
                                              uint16 ffe_tap2, uint16 ffe_tap34, uint16 ffe_tap3, uint16 ffe_tap4)
{
    uint16 ffe_tap1_gray_LSB = 0;
    uint16 ffe_tap1_gray_MSB = 0;
    uint16 ffe_tap1_gray = 0;
    uint16 ffe_tap234_gray_LSB = 0;
    uint16 ffe_tap234_gray_MSB = 0;
    uint16 ffe_tap234_gray = 0;
    uint16 ffe_tap2_gray_LSB = 0;
    uint16 ffe_tap2_gray_MSB = 0;
    uint16 ffe_tap2_gray = 0;
    uint16 ffe_tap34_gray_LSB = 0;
    uint16 ffe_tap34_gray_MSB = 0;
    uint16 ffe_tap34_gray = 0;
    uint16 ffe_tap3_gray_LSB = 0;
    uint16 ffe_tap3_gray_MSB = 0;
    uint16 ffe_tap3_gray = 0;
    uint16 ffe_tap4_gray_LSB = 0;
    uint16 ffe_tap4_gray_MSB = 0;
    uint16 ffe_tap4_gray = 0;
    uint16 ffe_tap1_main1    = 0;
    uint16 ffe_tap1_main0    = 0;
    uint16 ffe_tap1_bin      = 0;
    uint16 ffe_tap234_main1  = 0;
    uint16 ffe_tap234_main0  = 0;
    uint16 ffe_tap234_bin    = 0;
    uint16 ffe_tap2_main1    = 0;
    uint16 ffe_tap2_main0    = 0;
    uint16 ffe_tap2_bin      = 0;
    uint16 ffe_tap34_main1   = 0;
    uint16 ffe_tap34_main0   = 0;
    uint16 ffe_tap34_bin     = 0;
    uint16 ffe_tap3_main1    = 0;
    uint16 ffe_tap3_main0    = 0;
    uint16 ffe_tap3_bin      = 0;
    uint16 ffe_tap4_main1    = 0;
    uint16 ffe_tap4_main0    = 0;
    uint16 ffe_tap4_bin      = 0;
    uint16 value             = 0;

    if(ffe_tap1 != 0xffff)
    {
        ffe_tap1_gray_LSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap1 & 0xf);
        ffe_tap1_gray_MSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap1 >> 4);
        ffe_tap1_gray = ((ffe_tap1_gray_MSB << 4) + ffe_tap1_gray_LSB) & 0xff;
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f2, 0x00ff, ffe_tap1_gray);
    }

    if(ffe_tap234 != 0xffff)
    {
        ffe_tap234_gray_LSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap234 & 0xf);
        ffe_tap234_gray_MSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY((ffe_tap234 >> 4) & 0x0f);
        ffe_tap234_gray = ((ffe_tap234_gray_MSB << 4) + ffe_tap234_gray_LSB) & 0xff;
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f2, 0xff00, ffe_tap234_gray);
    }

    if(ffe_tap2 != 0xffff)
    {
        ffe_tap2_gray_LSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap2 & 0xf);
        ffe_tap2_gray_MSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap2 >> 4);
        ffe_tap2_gray = ((ffe_tap2_gray_MSB << 4) + ffe_tap2_gray_LSB) & 0xff;
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f3, 0x00ff, ffe_tap2_gray);
    }

    if(ffe_tap34 != 0xffff)
    {
        ffe_tap34_gray_LSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap34 & 0xf);
        ffe_tap34_gray_MSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY((ffe_tap34 >> 4) & 0x0f);
        ffe_tap34_gray = ((ffe_tap34_gray_MSB << 4) + ffe_tap34_gray_LSB) & 0xff;
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f3, 0xff00, ffe_tap34_gray);
    }

    if(ffe_tap3 != 0xffff)
    {
        ffe_tap3_gray_LSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap3 & 0xf);
        ffe_tap3_gray_MSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap3 >> 4);
        ffe_tap3_gray = ((ffe_tap3_gray_MSB << 4) + ffe_tap3_gray_LSB) & 0xff;
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f4, 0x00ff, ffe_tap3_gray);
    }

    if(ffe_tap4 != 0xffff)
    {
        ffe_tap4_gray_LSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap4 & 0xf);
        ffe_tap4_gray_MSB = CTC_DIKT_TMM_SERDES_BIN_TO_GRAY(ffe_tap4 >> 4);
        ffe_tap4_gray = ((ffe_tap4_gray_MSB << 4) + ffe_tap4_gray_LSB) & 0xff;
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f4, 0xff00, ffe_tap4_gray);
    }

    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f2, 0x0fff, &value);
    ffe_tap1_main1 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f2, 0xf0ff, &value);
    ffe_tap1_main0 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    ffe_tap1_bin = (((ffe_tap1_main1) << 4) + ffe_tap1_main0)&0xFF;
    
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f2, 0xff0f, &value);
    ffe_tap234_main1 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f2, 0xfff0, &value);
    ffe_tap234_main0 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    ffe_tap234_bin = (((ffe_tap234_main1) << 4) + ffe_tap234_main0)&0xFF;
    
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f3, 0x0fff, &value);
    ffe_tap2_main1 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f3, 0xf0ff, &value);
    ffe_tap2_main0 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    ffe_tap2_bin = (((ffe_tap2_main1) << 4) + ffe_tap2_main0)&0xFF;
    
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f3, 0xff0f, &value);
    ffe_tap34_main1 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f3, 0xfff0, &value);
    ffe_tap34_main0 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    ffe_tap34_bin = (((ffe_tap34_main1) << 4) + ffe_tap34_main0)&0xFF;
    
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f4, 0x0fff, &value);
    ffe_tap3_main1 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f4, 0xf0ff, &value);
    ffe_tap3_main0 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    ffe_tap3_bin = (((ffe_tap3_main1) << 4) + ffe_tap3_main0)&0xFF;
    
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f4, 0xff0f, &value);
    ffe_tap4_main1 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f4, 0xfff0, &value);
    ffe_tap4_main0 = ctc_tmm_dkit_misc_serdes_gray_to_bin(value);
    ffe_tap4_bin = (((ffe_tap4_main1) << 4) + ffe_tap4_main0)&0xFF;

    CTC_DKIT_PRINT("tap1 0x%02x, tap234 0x%02x, tap2 0x%02x, tap34 0x%02x, tap3 0x%02x, tap4 0x%02x\n", 
        ffe_tap1_bin, ffe_tap234_bin, ffe_tap2_bin, ffe_tap34_bin, ffe_tap3_bin, ffe_tap4_bin);

    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_ffe_pol(uint8 lchip, uint8 serdes_id, uint16 ffe_pol1, uint16 ffe_pol2, 
                                              uint16 ffe_pol3, uint16 ffe_pol4)
{
    uint16 ffe_pol1_out = 0;
    uint16 ffe_pol2_out = 0;
    uint16 ffe_pol3_out = 0;
    uint16 ffe_pol4_out = 0;
    if((0xffff != ffe_pol1) && (0xffff != ffe_pol2) && (0xffff != ffe_pol3) && (0xffff != ffe_pol4))
    {
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f0, 0xfdff, ffe_pol1);
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f0, 0xfeff, ffe_pol2);
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f0, 0xff7f, ffe_pol3);
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f0, 0xffbf, ffe_pol4);
    }
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f0, 0xfdff, &ffe_pol1_out);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f0, 0xfeff, &ffe_pol2_out);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f0, 0xff7f, &ffe_pol3_out);
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x00f0, 0xffbf, &ffe_pol4_out);

    CTC_DKIT_PRINT("pol1 0x%02x, pol2 0x%02x, pol3 0x%02x, pol4 0x%02x\n", ffe_pol1_out, ffe_pol2_out, ffe_pol3_out, ffe_pol4_out);
    
    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_sel_phase(uint8 lchip, uint16 serdes_id, uint8 phase)
{
    if(phase == 0)
    {
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x6e, 0xff00, 0);
    }
    else
    {
        (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x6e, 0xff00, (uint16)((0xff)-(0x1<<(phase-1))));
    }
    return CLI_SUCCESS;
}

uint32
_ctc_tmm_dkit_misc_serdes_err_cntr(uint8 lchip, uint16 serdes_id, uint8 pri_en, uint16 ms, int cntr_all[])
{
    uint32 cntr_1_i;
    uint32 cntr_2_i;
    uint32 cntr_3_i;
    uint32 cntr_4_i;
    uint32 cntr_5_i;
    uint32 cntr_6_i;
    uint32 cntr_7_i;
    uint32 cntr_8_i;
    uint32 cntr_9_i;
    uint32 cntr_a_i;
    uint32 cntr_b_i;
    uint32 cntr_c_i;
    uint32 cntr_1_p;
    uint32 cntr_2_p;
    uint32 cntr_3_p;
    uint32 cntr_4_p;
    uint32 cntr_5_p;
    uint32 cntr_6_p;
    uint32 cntr_7_p;
    uint32 cntr_8_p;
    uint32 cntr_9_p;
    uint32 cntr_a_p;
    uint32 cntr_b_p;
    uint32 cntr_c_p;
    uint16 high16;
    uint16 low16;

    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x52, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x53, 0, &low16);
    cntr_1_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x54, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x55, 0, &low16);
    cntr_2_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x56, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x57, 0, &low16);
    cntr_3_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x58, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x59, 0, &low16);
    cntr_4_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5a, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5b, 0, &low16);
    cntr_5_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5c, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5d, 0, &low16);
    cntr_6_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5e, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5f, 0, &low16);
    cntr_7_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x60, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x61, 0, &low16);
    cntr_8_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x62, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x63, 0, &low16);
    cntr_9_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x64, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x65, 0, &low16);
    cntr_a_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x66, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x67, 0, &low16);
    cntr_b_i = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x68, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x69, 0, &low16);
    cntr_c_i = ((uint32)high16 << 16) + low16;

    sal_task_sleep(ms);

    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x52, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x53, 0, &low16);
    cntr_1_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x54, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x55, 0, &low16);
    cntr_2_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x56, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x57, 0, &low16);
    cntr_3_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x58, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x59, 0, &low16);
    cntr_4_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5a, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5b, 0, &low16);
    cntr_5_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5c, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5d, 0, &low16);
    cntr_6_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5e, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x5f, 0, &low16);
    cntr_7_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x60, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x61, 0, &low16);
    cntr_8_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x62, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x63, 0, &low16);
    cntr_9_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x64, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x65, 0, &low16);
    cntr_a_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x66, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x67, 0, &low16);
    cntr_b_p = ((uint32)high16 << 16) + low16;
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x68, 0, &high16);  
    (void)_ctc_tmm_dkit_misc_read_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x69, 0, &low16);
    cntr_c_p = ((uint32)high16 << 16) + low16;

    /*cntr = cntr_p - cntr_i*/
    cntr_all[1] = cntr_1_p - cntr_1_i;
    cntr_all[2] = cntr_2_p - cntr_2_i;
    cntr_all[3] = cntr_3_p - cntr_3_i;
    cntr_all[4] = cntr_4_p - cntr_4_i;
    cntr_all[5] = cntr_5_p - cntr_5_i;
    cntr_all[6] = cntr_6_p - cntr_6_i;
    cntr_all[7] = cntr_7_p - cntr_7_i;
    cntr_all[8] = cntr_8_p - cntr_8_i;
    cntr_all[9] = cntr_9_p - cntr_9_i;
    cntr_all[10] = cntr_a_p - cntr_a_i;
    cntr_all[11] = cntr_b_p - cntr_b_i;
    cntr_all[12] = cntr_c_p - cntr_c_i;
    cntr_all[0] = cntr_all[1] + cntr_all[2] + cntr_all[3] + cntr_all[4] +
                 cntr_all[5] + cntr_all[6] + cntr_all[7] + cntr_all[8] +
                 cntr_all[9] + cntr_all[10] + cntr_all[11] + cntr_all[12];

    if(pri_en == 1)
    {
        CTC_DKIT_PRINT("prbs check error: %d\n", cntr_all[0]);
        CTC_DKIT_PRINT("cntr 1: %d\n",         cntr_all[1]);
        CTC_DKIT_PRINT("cntr 2: %d\n",         cntr_all[2]);
        CTC_DKIT_PRINT("cntr 3: %d\n",         cntr_all[3]);
        CTC_DKIT_PRINT("cntr 4: %d\n",         cntr_all[4]);
        CTC_DKIT_PRINT("cntr 5: %d\n",         cntr_all[5]);
        CTC_DKIT_PRINT("cntr 6: %d\n",         cntr_all[6]);
        CTC_DKIT_PRINT("cntr 7: %d\n",         cntr_all[7]);
        CTC_DKIT_PRINT("cntr 8: %d\n",         cntr_all[8]);
        CTC_DKIT_PRINT("cntr 9: %d\n",         cntr_all[9]);
        CTC_DKIT_PRINT("cntr a: %d\n",         cntr_all[10]);
        CTC_DKIT_PRINT("cntr b: %d\n",         cntr_all[11]);
        CTC_DKIT_PRINT("cntr c: %d\n",         cntr_all[12]);
    }

    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_prev_func(uint8 lchip, uint16 serdes_id, uint16 en, uint16 prev)
{
    (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x45, 0xfdff, en);
    (void)_ctc_tmm_dkit_misc_write_serdes_wapper(lchip, serdes_id, CTC_DKIT_SERDES_ALL, 0x45, 0xfe7f, prev);
    return CLI_SUCCESS;
}

int32
_ctc_tmm_dkit_misc_serdes_phase_err(uint8 lchip, uint16 serdes_id, uint8 pri_en, uint16 ms)
{
    uint8 phase;
    uint8 err;
    int data[9][13] = {{0}};
    
    (void)_ctc_tmm_dkit_misc_serdes_prev_func(lchip, serdes_id, 1, 0);
    for(phase = 0; phase < 9; phase++)
    {
        (void)_ctc_tmm_dkit_misc_serdes_sel_phase(lchip, serdes_id, phase);
        (void)_ctc_tmm_dkit_misc_serdes_err_cntr(lchip, serdes_id, 0, ms, data[phase]);
    }
    if(pri_en == 1)
    {
        CTC_DKIT_PRINT("\n---------------------------------------------------------- Prev 00 ----------------------------------------------------------------\n");
        CTC_DKIT_PRINT("PrbsErrCntr:     total,    0001,    0010,    0011,    0100,    0110,    0111,    1000,    1001,    1011,    1100,    1101,    1110,\n");
        for(phase = 0; phase < 9; phase++)
        {
            if(0 == phase)
            {
                CTC_DKIT_PRINT("\nphase all: ");
            }
            else
            {
                CTC_DKIT_PRINT("\nphase %03X: ", phase);
                for(err = 0; err < 13; err++)
                {
                    if(0 == err) CTC_DKIT_PRINT("%11d,", data[phase][err]);
                    else CTC_DKIT_PRINT("%7d,", data[phase][err]);
                }
            }
        }
    }
    CTC_DKIT_PRINT("\n");
    
    (void)_ctc_tmm_dkit_misc_serdes_prev_func(lchip, serdes_id, 1, 1);
    for(phase = 0; phase < 9; phase++)
    {
        (void)_ctc_tmm_dkit_misc_serdes_sel_phase(lchip, serdes_id, phase);
        (void)_ctc_tmm_dkit_misc_serdes_err_cntr(lchip, serdes_id, 0, ms, data[phase]);
    }
    if(pri_en == 1)
    {
        CTC_DKIT_PRINT("\n---------------------------------------------------------- Prev 01 ----------------------------------------------------------------\n");
        CTC_DKIT_PRINT("PrbsErrCntr:     total,    0001,    0010,    0011,    0100,    0110,    0111,    1000,    1001,    1011,    1100,    1101,    1110,\n");
        for(phase = 0; phase < 9; phase++)
        {
            if(0 == phase)
            {
                CTC_DKIT_PRINT("\nphase all: ");
            }
            else
            {
                CTC_DKIT_PRINT("\nphase %03X: ", phase);
                for(err = 0; err < 13; err++)
                {
                    if(0 == err) CTC_DKIT_PRINT("%11d,", data[phase][err]);
                    else CTC_DKIT_PRINT("%7d,", data[phase][err]);
                }
            }
        }
    }
    CTC_DKIT_PRINT("\n");
    
    (void)_ctc_tmm_dkit_misc_serdes_prev_func(lchip, serdes_id, 1, 2);
    for(phase = 0; phase < 9; phase++)
    {
        (void)_ctc_tmm_dkit_misc_serdes_sel_phase(lchip, serdes_id, phase);
        (void)_ctc_tmm_dkit_misc_serdes_err_cntr(lchip, serdes_id, 0, ms, data[phase]);
    }
    if(pri_en == 1)
    {
        CTC_DKIT_PRINT("\n---------------------------------------------------------- Prev 10 ----------------------------------------------------------------\n");
        CTC_DKIT_PRINT("PrbsErrCntr:     total,    0001,    0010,    0011,    0100,    0110,    0111,    1000,    1001,    1011,    1100,    1101,    1110,\n");
        for(phase = 0; phase < 9; phase++)
        {
            if(0 == phase)
            {
                CTC_DKIT_PRINT("\nphase all: ");
            }
            else
            {
                CTC_DKIT_PRINT("\nphase %03X: ", phase);
                for(err = 0; err < 13; err++)
                {
                    if(0 == err) CTC_DKIT_PRINT("%11d,", data[phase][err]);
                    else CTC_DKIT_PRINT("%7d,", data[phase][err]);
                }
            }
        }
    }
    CTC_DKIT_PRINT("\n");
    
    (void)_ctc_tmm_dkit_misc_serdes_prev_func(lchip, serdes_id, 1, 3);
    for(phase = 0; phase < 9; phase++)
    {
        (void)_ctc_tmm_dkit_misc_serdes_sel_phase(lchip, serdes_id, phase);
        (void)_ctc_tmm_dkit_misc_serdes_err_cntr(lchip, serdes_id, 0, ms, data[phase]);
    }
    if(pri_en == 1)
    {
        CTC_DKIT_PRINT("\n---------------------------------------------------------- Prev 11 ----------------------------------------------------------------\n");
        CTC_DKIT_PRINT("PrbsErrCntr:     total,    0001,    0010,    0011,    0100,    0110,    0111,    1000,    1001,    1011,    1100,    1101,    1110,\n");
        for(phase = 0; phase < 9; phase++)
        {
            if(0 == phase)
            {
                CTC_DKIT_PRINT("\nphase all: ");
            }
            else
            {
                CTC_DKIT_PRINT("\nphase %03X: ", phase);
                for(err = 0; err < 13; err++)
                {
                    if(0 == err) CTC_DKIT_PRINT("%11d,", data[phase][err]);
                    else CTC_DKIT_PRINT("%7d,", data[phase][err]);
                }
            }
        }
    }
    CTC_DKIT_PRINT("\n");
    
    return CLI_SUCCESS;
}

/*for temp intr*/
 typedef struct _ctc_tmm_dkit_check_reg_info_s
 {
     uint32 tbl_id;
     uint32 fld_id;
 }_ctc_tmm_dkit_check_reg_info_t;

 #define INTR_OP_READ       0
 #define INTR_OP_CLEAR      1
 #define INTR_OP_MASK       2
 #define INTR_OP_UNMASK     3
/*end of for temp intr*/

const _ctc_tmm_dkit_check_reg_info_t g_check_list[] = {

    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun1_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun2_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun3_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun4_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun5_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun6_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun7_f},

    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun1_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun2_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun3_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun4_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun5_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun6_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun7_f},

    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},
    {McPcsX8LanesInterruptNormal_t, McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},

    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun0_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun1_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun2_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun3_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun4_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun5_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun6_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeRxBufOverrun7_f},

    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun0_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun1_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun2_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun3_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun4_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun5_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun6_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufOverrun7_f},

    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun0_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun1_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun2_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun3_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun4_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun5_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun6_f},
    {McPcsX8LanesInterruptNormal_t,McPcsX8LanesInterruptNormal_intrFlexeTxBufUnderrun7_f},

    {McRateCompFifoOverflowInterruptStatusB0_t,McRateCompFifoOverflowInterruptStatusB0_val_f},
    {McRateCompFifoOverflowInterruptStatusB0_t,McRateCompFifoOverflowInterruptStatusB1_val_f},
    {McRateCompFifoOverflowInterruptStatusB0_t,McRateCompFifoOverflowInterruptStatusB2_val_f},

    {RxMcOutputFifoOverflowInterruptStatus0_t,RxMcOutputFifoOverflowInterruptStatus0_val_f},
    {RxMcOutputFifoOverflowInterruptStatus0_t,RxMcOutputFifoUnderflowInterruptStatus0_val_f},
};

void _ctc_tmm_dkit_check_abnormal_intr(uint8 lchip, uint8 op)
{
    uint32 tbl_id       = 0;
    uint32 fld_id       = 0;
    uint32 cmd          = 0;
    uint32 index        = 0;
    uint32 value        = 0;
    uint8 inst_id       = 0;
    uint8 inst_num      = 0;
    uint8 loop          = 0;
    ds_t  ds            = {0};
    char  fld_str[64]   = {0};

    if(INTR_OP_READ == op) /* read and print */
    {
        for(loop = 0; loop < sizeof(g_check_list)/sizeof(g_check_list[0]); loop++)
        {
            tbl_id = g_check_list[loop].tbl_id;
            fld_id = g_check_list[loop].fld_id;
            inst_num = TABLE_ADDR_NUM(lchip, tbl_id);
            drv_usw_get_field_string_by_id(lchip, tbl_id, fld_id, fld_str);
        
            for(inst_id = 0; inst_id < inst_num; inst_id++)
            {
                index = DRV_INS(inst_id, 0);
                cmd   = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
                DRV_IOCTL(lchip, index, cmd, &ds);
                DRV_IOR_FIELD(lchip, tbl_id, fld_id, &value, &ds);

                if (0 != value)
                {
                    CTC_DKIT_PRINT("[FlexE] Attention! abnormal intr happens. tbl:%s fld:%s inst:%d value:%x\n", \
                        TABLE_NAME(lchip, tbl_id), fld_str, inst_id, value);
                }
            }
        }

        drv_usw_chip_read(lchip, 0x60000020, &value);
        if (0 != value)
        {
            CTC_DKIT_PRINT("[FlexE] Attention! abnormal intr happens. address:0x60000020 value:%x\n", value);
        }
        drv_usw_chip_read(lchip, 0x68000020, &value);
        if (0 != value)
        {
            CTC_DKIT_PRINT("[FlexE] Attention! abnormal intr happens. address:0x68000020 value:%x\n", value);
        }
        drv_usw_chip_read(lchip, 0x60000018, &value);
        if (0 != value)
        {
            CTC_DKIT_PRINT("[FlexE] Attention! abnormal intr happens. address:0x60000018 value:%x\n", value);
        }
        drv_usw_chip_read(lchip, 0x6000001c, &value);
        if (0 != value)
        {       
            CTC_DKIT_PRINT("[FlexE] Attention! abnormal intr happens. address:0x6000001c value:%x\n", value);
        }
        drv_usw_chip_read(lchip, 0x68000018, &value);
        if (0 != value)
        {    
            CTC_DKIT_PRINT("[FlexE] Attention! abnormal intr happens. address:0x68000018 value:%x\n", value);
        }  
        drv_usw_chip_read(lchip, 0x6800001c, &value);
        if (0 != value)
        {    
            CTC_DKIT_PRINT("[FlexE] Attention! abnormal intr happens. address:0x6800001c value:%x\n", value);
        }
    }
    else if(INTR_OP_CLEAR == op || INTR_OP_MASK == op || INTR_OP_UNMASK == op)
    {
        for(loop = 0; loop < sizeof(g_check_list)/sizeof(g_check_list[0]); loop++)
        {
            tbl_id = g_check_list[loop].tbl_id;
            fld_id = g_check_list[loop].fld_id;
            inst_num = TABLE_ADDR_NUM(lchip, tbl_id);
            
            for(inst_id = 0; inst_id < inst_num; inst_id++)
            {
                sal_memset(ds, 0, sizeof(ds_t));

                value = 1;
                DRV_IOW_FIELD(lchip, tbl_id, fld_id, &value, &ds);

                index = DRV_INS(inst_id, op);
                cmd   = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
                DRV_IOCTL(lchip, index, cmd, &ds);
            }
        }
        drv_usw_chip_read(lchip, 0x60000020, &value);
        drv_usw_chip_read(lchip, 0x68000020, &value);
        drv_usw_chip_read(lchip, 0x60000018, &value);
        drv_usw_chip_read(lchip, 0x6000001c, &value);
        drv_usw_chip_read(lchip, 0x68000018, &value);
        drv_usw_chip_read(lchip, 0x6800001c, &value);
    }

}

int32
ctc_tmm_dkit_misc_serdes_diag(uint8 lchip, void* para)
{
    uint32 diag_id = 0;
    uint8  serdes_id = 0;
    ctc_dkit_serdes_diag_para_t* p_para = (ctc_dkit_serdes_diag_para_t*)para;

    if((p_para->param_cnt > 63) || (p_para->param_cnt == 0) || (p_para->p_param == NULL))
    {
        CTC_DKIT_PRINT("Invalid param number!\n");
        return CLI_SUCCESS;
    }
    serdes_id = (uint8)(p_para->serdes_id);
    if(serdes_id > 99)
    {
        CTC_DKIT_PRINT("Invalid serdes id %u!\n", serdes_id);
        return CLI_SUCCESS;
    }
    diag_id = p_para->p_param[0];
    switch(diag_id)
    {
        case 0:
            if(7 != p_para->param_cnt)
            {
                CTC_DKIT_PRINT("ffe_taps: Input param number illegal, gaving %u expecting 6.\n", p_para->param_cnt-1);
                return CLI_SUCCESS;
            }
            (void)_ctc_tmm_dkit_misc_serdes_ffe_taps(lchip, serdes_id, (uint16)p_para->p_param[1], (uint16)p_para->p_param[2], 
                (uint16)p_para->p_param[3], (uint16)p_para->p_param[4], (uint16)p_para->p_param[5], (uint16)p_para->p_param[6]);
            break;
        case 1:
            if(5 != p_para->param_cnt)
            {
                CTC_DKIT_PRINT("ffe_pol: Input param number illegal, gaving %u expecting 4.\n", p_para->param_cnt-1);
                return CLI_SUCCESS;
            }
            (void)_ctc_tmm_dkit_misc_serdes_ffe_pol(lchip, serdes_id, (uint16)p_para->p_param[1], (uint16)p_para->p_param[2], 
                (uint16)p_para->p_param[3], (uint16)p_para->p_param[4]);
            break;
        case 2:
            (void)_ctc_tmm_dkit_misc_serdes_phase_err(lchip, serdes_id, 1, (uint16)p_para->p_param[1]);
            break;
        case 3:
            if(2 != p_para->param_cnt)
            {
                CTC_DKIT_PRINT("abnormal intr check : Input param number illegal, gaving %u expecting 1.\n", p_para->param_cnt-1);
            }
            (void)_ctc_tmm_dkit_check_abnormal_intr(lchip, (uint8)p_para->p_param[1]);
            break;
        default:
            break;
    }
    
    return CLI_SUCCESS;
}

void *
_ctc_tmm_dkit_misc_serdes_ctl_parm_convert(ctc_dkit_serdes_ctl_para_t *p_para)
{
    ctc_dkit_tmm_serdes_ctl_loopback_t  *loopback_param = NULL;
    ctc_dkit_tmm_serdes_ctl_prbs_t      *prbs_param = NULL;
    ctc_dkit_tmm_serdes_ctl_eye_t       *eye_param = NULL;
    ctc_dkit_tmm_serdes_ctl_ffe_t       *ffe_param = NULL;
    ctc_dkit_tmm_serdes_ctl_pol_check_t  *pol_check_param = NULL;
    ctc_dkit_tmm_serdes_ctl_dfe_t       *dfe_param = NULL;
    ctc_dkit_tmm_serdes_ctl_fw_t        *fw_param = NULL;
    ctc_dkit_tmm_serdes_ctl_bathtub_t   *bathtub_param = NULL;
    
    void *p_data = NULL;

    switch (p_para->type)
    {
        case CTC_DKIT_SERDIS_CTL_LOOPBACK:
            loopback_param = (ctc_dkit_tmm_serdes_ctl_loopback_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmm_serdes_ctl_loopback_t));
            if (NULL == loopback_param)
            {
                break;
            }
            loopback_param->serdes_id = p_para->serdes_id;
            loopback_param->oper = p_para->para[0];
            loopback_param->mode = p_para->para[1];
            p_data = loopback_param;
            break;
        case CTC_DKIT_SERDIS_CTL_PRBS:
            prbs_param = (ctc_dkit_tmm_serdes_ctl_prbs_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmm_serdes_ctl_prbs_t));
            if (NULL == prbs_param)
            {
                break;
            }
            prbs_param->lchip = p_para->lchip;
            prbs_param->serdes_id = p_para->serdes_id;
            prbs_param->oper = p_para->para[0];
            prbs_param->prbs_pattern = p_para->para[1];
            prbs_param->is_keep = p_para->para[2];
            prbs_param->delay_before_check = p_para->para[3];
            prbs_param->error_count = p_para->para[4];
            prbs_param->str = p_para->str;
            p_data = prbs_param;
            break;
        case CTC_DKIT_SERDIS_CTL_EYE:
            eye_param = (ctc_dkit_tmm_serdes_ctl_eye_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmm_serdes_ctl_eye_t));
            if (NULL == eye_param)
            {
                break;
            }
            eye_param->serdes_id = p_para->serdes_id;
            eye_param->eye_type = p_para->para[0];
            eye_param->read_times = p_para->para[1];
            p_data = eye_param;
            break;
        case CTC_DKIT_SERDIS_CTL_FFE:
            ffe_param = (ctc_dkit_tmm_serdes_ctl_ffe_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmm_serdes_ctl_ffe_t));
            if (NULL == ffe_param)
            {
                break;
            }
            ffe_param->serdes_id = p_para->serdes_id;
            ffe_param->dest_serdes_id = p_para->para[0];
            ffe_param->prbs_pattern = p_para->para[1];
            ffe_param->threshold = p_para->para[2];
            ffe_param->delay = p_para->para[3];
            ffe_param->str = p_para->str;
            ffe_param->ffe = &p_para->ffe;
            p_data = ffe_param;
            break;
        case CTC_DKIT_SERDIS_CTL_STATUS:
        case CTC_DKIT_SERDIS_CTL_ISI:
        case CTC_DKIT_SERDIS_CTL_DELAT_PH:
            break;
        case CTC_DKIT_SERDIS_CTL_POLR_CHECK:
            pol_check_param = (ctc_dkit_tmm_serdes_ctl_pol_check_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmm_serdes_ctl_pol_check_t));
            if (NULL == pol_check_param)
            {
                break;
            }
            pol_check_param->serdes_id = p_para->serdes_id;
            pol_check_param->paired_serdes_id = p_para->para[0];
            p_data = eye_param;
            break;
        case CTC_DKIT_SERDIS_CTL_DFE:
        case CTC_DKIT_SERDIS_CTL_GET_DFE:
            dfe_param = (ctc_dkit_tmm_serdes_ctl_dfe_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmm_serdes_ctl_dfe_t));
            if (NULL == dfe_param)
            {
                break;
            }
            dfe_param->serdes_id = p_para->serdes_id;
            dfe_param->oper = p_para->para[0];
            dfe_param->taps[0] = (uint8)(p_para->para[1] & 0xff);
            dfe_param->taps[1] = (uint8)(p_para->para[1] & (0xff << 8));
            dfe_param->taps[2] = (uint8)(p_para->para[1] & (0xff << 16));
            dfe_param->taps[3] = (uint8)(p_para->para[1] & (0xff << 24));
            dfe_param->taps[4] = (uint8)(p_para->para[2] & 0xff);
            p_data = dfe_param;
            break;
        case CTC_DKIT_SERDIS_CTL_FW:
            fw_param = (ctc_dkit_tmm_serdes_ctl_fw_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmm_serdes_ctl_fw_t));
            if (NULL == fw_param)
            {
                break;
            }
            fw_param->serdes_id = p_para->serdes_id;
            fw_param->oper = p_para->para[0];
            p_data = fw_param;
            break;
        case CTC_DKIT_SERDIS_CTL_BATHTUB:
            bathtub_param = (ctc_dkit_tmm_serdes_ctl_bathtub_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmm_serdes_ctl_bathtub_t));
            if (NULL == bathtub_param)
            {
                break;
            }
            bathtub_param->serdes_id = p_para->serdes_id;
            bathtub_param->oper = p_para->para[0];
            bathtub_param->depth = p_para->para[1];
            p_data = bathtub_param;
            break;
        default:
            break;
    }
    
    return p_data;
}

int32
ctc_tmm_dkit_misc_serdes_ctl(void* p_para)
{
    uint8 lchip;
    ctc_dkit_serdes_ctl_para_t* p_serdes_para = (ctc_dkit_serdes_ctl_para_t*)p_para;
    void *p_param = NULL;

    DKITS_PTR_VALID_CHECK(p_serdes_para);
    lchip = p_serdes_para->lchip;
    CTC_DKIT_LCHIP_CHECK(lchip);
    DRV_INIT_CHECK(lchip);

    p_param = _ctc_tmm_dkit_misc_serdes_ctl_parm_convert(p_serdes_para);

    if((CTC_DKIT_SERDIS_CTL_STATUS != p_serdes_para->type) && (CTC_DKIT_SERDIS_CTL_ISI != p_serdes_para->type) &&  \
        (CTC_DKIT_SERDIS_CTL_DELAT_PH != p_serdes_para->type))
    {
        DKITS_PTR_VALID_CHECK(p_param);
    }
    
    switch (p_serdes_para->type)
    {
        case CTC_DKIT_SERDIS_CTL_LOOPBACK:
            _ctc_tmm_dkit_misc_serdes_loopback(lchip, p_param);
            break;
        case CTC_DKIT_SERDIS_CTL_PRBS:
            _ctc_tmm_dkit_misc_serdes_prbs(lchip, p_param);
            break;
        case CTC_DKIT_SERDIS_CTL_EYE:
            _ctc_tmm_dkit_misc_serdes_eye(lchip, p_param);
            break;
        case CTC_DKIT_SERDIS_CTL_FFE:
            _ctc_tmm_dkit_misc_serdes_ffe_scan(lchip, p_param);
            break;
        case CTC_DKIT_SERDIS_CTL_STATUS:
            _ctc_tmm_dkit_misc_serdes_status(lchip, p_serdes_para->serdes_id, NULL);
            break;
        case CTC_DKIT_SERDIS_CTL_POLR_CHECK:
            _ctc_tmm_dkit_misc_serdes_polr_check(lchip, p_param);
            break;
        case CTC_DKIT_SERDIS_CTL_DFE:
            _ctc_tmm_dkit_misc_serdes_dfe_set_en(lchip, p_param);
            break;
        case CTC_DKIT_SERDIS_CTL_GET_DFE:
            _ctc_tmm_dkit_misc_serdes_show_dfe(lchip, p_param);
            p_serdes_para->para[4] = 1; /*use chip customization show format*/
            break;
        case CTC_DKIT_SERDIS_CTL_FW:
            _ctc_tmm_dkit_misc_serdes_fw(lchip, p_param);
            break;
        case CTC_DKIT_SERDIS_CTL_ISI:
            _ctc_tmm_dkit_misc_serdes_dump_ISI(lchip, p_serdes_para->serdes_id, NULL);
            break;
        case CTC_DKIT_SERDIS_CTL_DELAT_PH:
            _ctc_tmm_dkit_misc_serdes_get_delta_ph(lchip, p_serdes_para->serdes_id);
            break;
        case CTC_DKIT_SERDIS_CTL_BATHTUB:
            ctc_tmm_dkit_misc_serdes_do_bathtub(lchip, p_param);
            break;
        default:
            break;
    }

    mem_free(p_param);

    return CLI_SUCCESS;
}

